First up in the server interaction portion of this Angular tutorial is R(ead) of CRUD, and we see how to retrieve data using RxJS as an intermediary for making HTTP GET calls. There were unfortunately a few pieces of unexplained magic, such as the presence of a method
getHeroNo404() that was explicitly called out in a sidebar yet whose purpose is, strangely, not explained in that sidebar. We can infer it has something to do with error handling, since HTTP 404 is a common error and the tutorial started covering error handling. A very important part of writing any web pap, since HTTP fails all the time for factors out of our control. Still, it would have been nice to know more about how
getHeroNo404() fits into the picture.
Next up is U(pdate) of CRUD, and while I’m happy to see some compile-time verification, there’s still some sadness that a lot are still left up to runtime. When I made a mistake in binding button
(click)="save()" without defining a
save() function in TS, it did not generate a compile time error even though at first glance all the pieces to detect this at compile time are present. In reality, it’s not until runtime and a click on the button do we get the error. And again we need to learn to interpret the error. Because while the lack of
save() is correct, the user never declared anything named
ctx_r3 and so we had to work backwards by guessing what Angular framework had created on our behalf.
ERROR TypeError: ctx_r3.save is not a function
at HeroDetailComponent_div_0_Template_button_click_12_listener (hero-detail.component.html:10)
at executeListenerWithErrorHandling (core.js:14317)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:14352) at HTMLButtonElement.<anonymous> (platform-browser.js:582)
at ZoneDelegate.invokeTask (zone-evergreen.js:399)
at Object.onInvokeTask (core.js:27428)
at ZoneDelegate.invokeTask (zone-evergreen.js:398)
at Zone.runTask (zone-evergreen.js:167)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:480)
at invokeTask (zone-evergreen.js:1621) defaultErrorLogger @ core.js:4197 handleError @ core.js:4245 handleError @ core.js:8627 executeListenerWithErrorHandling @ core.js:14320 wrapListenerIn_markDirtyAndPreventDefault @ core.js:14352 (anonymous) @ platform-browser.js:582 invokeTask @ zone-evergreen.js:399 onInvokeTask @ core.js:27428 invokeTask @ zone-evergreen.js:398 runTask @ zone-evergreen.js:167 invokeTask @ zone-evergreen.js:480 invokeTask @ zone-evergreen.js:1621 globalZoneAwareCallback @ zone-evergreen.js:1647
Thankfully this was towards the end of the tutorial and chances are good anyone following along would have seen enough to know how to diagnose these problems. Because it certainly doesn’t get any easier as the tutorial continues to the remainder of CRUD.
After getting an introduction to Angular services, I have some understanding but also know I still have a lot to read up on. I see several practice projects ahead, implementing my own Angular services, before I really understand when and where to best utilize its powers. Setting them aside as exercises for later, I proceeded to the next section of the Tour of Heroes tutorial for implementing in-app navigation.
For me, this is the most novel part of learning how to develop a single-page application (SPA) with Angular as the specific example. HTML navigation is very much based on the idea of pages and navigation between them. The “single page” of SPA implies that pattern has been circumvented, but manged to do so while maintaining compatibility with web browsers and static content web servers. How was this magic accomplished?
The “a-ha” moment for me was when I learned about Angular server-side requirements. Even though the server only needs to serve static content and does not need to run any application code, the server needs to be configured so that HTTP404 (not found) errors be sent back to index.html. This is how the web browser’s address bar can change in response to application activity, while still staying on the same page, because those URLs will get sent back to the single HTML page and served up instead of the HTTP404 error.
And when the page loads up (or stays up, really) in response to that new URL, that attempted URL is sent back into the page as well. This informs the SPA as to what to display in response. The code performing this processing is referred to as the router. For this tutorial, we are instructed to pull in an Angular module and call it the AppRoutingModule. The interesting implication here is that despite being a key part of SPAs, the router is “just another module” and can be modified or swapped out with different router modules as needed. I don’t know when this would be done or why, but it’s always good to see flexibility in an architecture.
Splitting related functionality into its own Angular component results in improved organization and maintenance. However, the structure of Angular components are focused on delivering a visual representation on screen. Sometimes we want to organize a set of related code into a logical unit that has no direct on-screen representation, and that is why the tutorial teaches us how to create Angular services.
Since there is nothing on screen, Angular services are a little more abstract and involve moving parts we haven’t seen yet. I re-read “Provide the HeroService” section several times and I still don’t feel like I have a good grasp of “service”, “provider”, and “injector”. I don’t see why “service” and “provider” are two different concepts, as the tutorial provider instantiates the service class. Perhaps a service can be provided by one of several different providers? Or perhaps a service class can be created by multiple providers? Or is there a 1:1 relationship but they need to be kept separate for some reason I don’t understand? That is an exercise left for later. As for injectors, we use a single global injector in the tutorial. Having multiple injectors — and when it would make sense to do so — is outside the scope of this tutorial.
It didn’t help that the section started with one bear of a compound sentence:
You must make the
HeroService available to the dependency injection system before Angular can inject it into the
HeroesComponent by registering a provider.
There are multiple ways to parse this sentence. My initial reading was “You must (make the
HeroService available to the dependency injection system) before (Angular can inject it into the
HeroesComponent by registering a provider.)” but now I think it is “You must (make the
HeroService available to the dependency injection system) before (Angular can inject it into the
HeroesComponent) by (registering a provider).” But either way I think this sentence should be broken up and rewritten. If I grow in my Angular knowledge to understand what’s going on (which I don’t at the moment) I can try my hand at rewriting that sentence and submit a pull request.
Which is a fair description of this services section of the Angular tutorial, actually. The Heroes service is followed by another service example to represent Message. And given the overlap, Message service included fewer explanations than earlier. I think I’m still mostly keeping up, but there’s definitely less comprehension and understanding as I copy and paste. Thankfully I had an easier time following the next section on in-app navigation.
I had hoped they would continue discussion project organization to how this relates to Angular modules, but they did not. I assume Angular modules apply the similar concept to a larger scale, each module a collection of components, but I don’t know for sure and haven’t seen how it would be useful.
The componentization tutorial has one aspect unique among all of these tutorial pages: After following through all the steps on the page, the end-user visible web app looks exactly the same. All our effort was spent organizing code behind the scenes without disturbing the user facing visible appearance. I thought it was neat but some may find it pointless. Either way, this would be the last time we “do nothing” in this tutorial. Following changes are more consequential.
Editing the name of a single non-copyright-infringing superhero isn’t terribly exciting by itself. We demand a world of many superheroes! Thus we move on to part 2 of the Angular “Tour of Heroes” tutorial: display a selectable list which builds our experience using Angular directives in the template HTML.
During this segment, we have many more opportunities to see what happens when we do something before setting up all the necessary support infrastructure. Meaning we got to see more error messages of a broken app before we proceed to fix it. I love this approach as there’s very little penalty to a momentarily broken Angular app. The more experience we can pick up with Angular errors during a tutorial, the better it is for us down the line when we see it again due to our own mistakes.
I also realized they’ve started showing just short excerpts for the reader to put into their projects. The template (HTML) and class (TypeScript) excerpts were fairly well explained, but following precedent, CSS changes were less well explained. This is not a CSS class, but there was one part I couldn’t follow at all: the CSS select binding. I don’t see how
[class.selected]="hero === selectedHero" ends up being
class="selected" in the HTML. I guess I have to look up “class binding” later.
Back to the topic of error messages, at the end of the tutorial I was left with an unresolved error.
ERROR in src/app/heroes/heroes.component.ts:12:3 - error TS2564: Property 'selectedHero' has no initializer and is not definitely assigned in the constructor.
12 selectedHero : Hero;
I thought it was odd for a tutorial to leave us with an error, so I started looking around for help and found this StackOverflow thread. Now I understand this is because I created my tutorial project with the
--strict flag. Since learning to operate under strict mode is an extra credit project I’ve given myself, and it is not preventing the app from running, I’ll ignore it for now and make plans to come back later. Code quality is always interesting to look into, in fact the next section is all about giving us tools to organize our Angular code.
Once the Angular workspace has been set up and initialized, our tutorial proceeds to the creation of the first Angular component: an editor for our main data object, the superhero. Of course we have to be able to rename them ourselves, because the tutorial gives us a list of non-copyright-infringing superhero names and we want to be able to correct them.
Instead of right-clicking as in StackBlitz, here we run
ng generate component to add a new component to our Angular application. And this time we took a little more time by getting into more detail on the individual steps and what they do. This helps us understand what each line of the boilerplate code does. It is mentioned that
ng generate also generates a test file for the component, though we don’t get into writing tests in this tutorial. Which is a bit of a shame. Hopefully I can find resources on writing tests elsewhere.
The most interesting mechanism demonstrated here is two-way databinding. I loved the fact that we added it in the template first, without supporting infrastructure, so we can see it break (and the corresponding error messages) before fixing it. I find this more instructive than a tutorial where we never see any of the error messages. But I did run into a brief problem where the two way bind didn’t seem to work. I entered a new name in the textbox and the hero name didn’t change. Oops. I saw no error messages and didn’t know how to start digging in to debug on my own, so I tried the simple thing first: I hit F5 on the browser to refresh. And that did the trick. Perhaps some caching has tripped me up? I’d like to know what happened. But now that the symptoms are gone, all I can do is proceed to the next tutorial step.
After a beginner is introduced to the objectives of Angular’s “Tour of Heroes” tutorial application, it’s time for us to start working on some actual code. And we start with creating a new project workspace by using Angular command line interface
This is a step skipped in the “Try It” shopping cart app, as the StackBlitz workspace was already partially populated for us. Now we are faced with a blank application template workspace exactly as we would see when we start striking out on our own later. So there were a few paragraphs helping to orient us in the structure of an Angular application workspace. I appreciated this because not every coding tutorial give us this explanation. Too many just dive straight into “Now open this file and start editing…” without saying anything about the default template structure.
Another step skipped in the “Try It” shopping cart app is the process of setting up a web server for development purposes. After all, we need some way to see the results of our handiwork locally and find problems before we publish to a real web server. StackBlitz handles that for us by default in their online workspace, but when working locally we’ll need to run
ng serve --open on our own.
And if everything is successful, we can see the default template, which is a simple HTML page with links to various Angular resources. Our first introductory task is to remove this default page and replace it with a blank page that has the application title. I found this to be a mild novelty. Usually our first task in a tutorial is to add some code, but this time around our first step is to remove code.
Once the placeholder was removed, we can proceed to seeing some Angular concepts in action:
- Component template — the HTML files sprinkled with Angular-specific directives that will be translated during compilation.
The third part of a standard Angular component, the component stylesheet, doesn’t get much attention. While CSS is a real and important part of a good looking web app, there’s nothing Angular specific about CSS used in this tutorial. So I understand why there’s very little focus on the why and how of styling an Angular application and we’re merely given our component stylesheets for copying and pasting. I’m fine with focusing on Angular now, and I plan to go (re)learn CSS elsewhere later.