Using setters for better @Input

When using @Input in our components, we can implement ngOnChanges to be notified whenever an input value has changed:

The above code works and would run whenever id or name are updated by the parent component. The problem is that this syntax can quickly become heavy when there are several @Inputs in your component.

Instead, we can do this:

Instead of using @Input() on a class property, we can use it on an ES6 setter function. The benefit of the setter syntax is that it makes it obvious what kind of code we’re running when the @Input value is set. No more ngOnChanges needed.

Build size budgets

As mentioned earlier in this newsletter, the size of your Javascript matters a lot, as our code has to be downloaded first, then parsed and interpreted by a browser, which will get slower and slower as the size of your app increases. This is why we want optimized production builds. And this is also why it’s always a good idea to keep track of the size of your production code after each build.

Fortunately, the Angular team has our back and integrated build budgets in the Angular CLI. You can use those budget settings to decide when to get a warning or even fail a build it your code becomes too big. This configuration happens in angular.json:

The above (default) budgets would warn you if your Javascript exceeds 500Kb in size and fail once the build exceeds 1Mb. Those are already part of your projects, so you don’t have to do anything to use them.

If you do continuous integration, your build will fail right after the commit that degraded your bundle size, making it easy to troubleshoot and fix the issue.

Most of the time, dependencies are the culprits. I remember coaching a client who needed some Excel-like features in the browser, and their build exploded to over 25MB because of a massive monolithic Javascript Excel library. Thanks to the build error, we knew that this library wouldn’t work, so we chose a lighter one instead.

In the past, I’ve also inherited projects where I would track our build size version after version. My client was amazed to see that despite adding features, the build was getting smaller and smaller after each release, thanks to Angular always being better at tree-shaking and having the incentive to clean up old code and make it smaller. When you start tracking a metric, you want to improve it!

Angular style guide

People often ask me the best way to organize their files/folders. While it’s mostly a matter of personal preference or a team decision, the recommendations of the Angular style guide are always good to follow.

For instance, when it comes down to folders, here’s what the official style guide says (the highlight is mine, as I find this to be true for myself):

What’s great about the Angular style guide is that it always provides why such approaches are recommended. As you can see, the above justifications make perfect sense.

Also, while some recommendations are purely naming conventions, others touch on architecture decisions, such as talking to the server through a service or using directives to enhance an element (somewhat similar to my earlier call to think more about directives instead of components).

ngFor trackBy for improved performance

We all use the ngFor directive on a daily basis. The directive is used to repeat a template as many times as needed based on an array of data we want to render. We covered how the directive exposes useful local variables in the past.

To help Angular perform DOM updates when items in the array are reordered, new items are added, or existing items are removed, we can add a trackBy attribute that specifies what unicity criteria Angular will use to track these additions/removals/reorderings:

Of course, this only helps if the array in question is subject to changes in the future. By default, Angular uses Object.is() to compare values in the array, which is somewhat similar to a === comparison.

In our case, we created a function that specifies how to track by _id:

That way, Angular will know how to compare objects efficiently and won’t perform DOM updates that aren’t needed, which can be a huge performance boost if you’re displaying a massive data table with thousands of records. You can see this example in action on Stackblitz here.

Prefer template-driven forms

International readers might not know that today is a public holiday in the United States as the country celebrates its birth and Independence. As a result, I’ll make today’s post very short but still useful.

Over the past couple of newsletters, I explained that template-driven forms are perfectly fine in most cases. A few years ago at ng-conf 2021, Ward Bell said he always uses template-driven forms and explained how he does that in less than 19 minutes.

If you’d rather read a short article, you can head to my “reactive template-driven forms” post where I showcase how template-driven forms are actually… a layer on top of reactive forms, and that you could still access reactive features on a template-driven form if you wanted to. I know, it’s mind-blowing!

Happy 4th of July if you’re in the US!

Reactive forms Observables

Last week, I gave you a simple decision framework to decide when to use reactive or template-driven forms.

As a matter of fact, the only reactive (meaning RxJs-friendly) piece of reactive forms is that FormGroup, FormArray, and FormControl all extend the AbstractControl class and, as a result, expose two different Observables:

Those two can be very powerful when used alongside some RxJs wizardry (see this tutorial on dynamic filtering with RxJs and Angular forms, for example). In their most simple form, we can use those to listen to changes in our form and react accordingly:

In the above example, we enable the city form control if a 5-digit zip code has been entered. Since we are subscribed to valueChanges, any future change of the zipcode value could enable/disable the city input.

The other Observable, statusChanges, focuses on validity changes only and returns one of the four following values:

Here is an example use case for statusChanges, which is more accurate than the previous example as this one would take into account all validation code relevant to the zip code:

Reactive or template-driven forms?

People are often conflicted when it comes down to forms with Angular. Should we use template-driven forms or reactive forms?

Here’s a simple answer:

  • If your form is dynamic (meaning: if the user selects this option, then add/enable or remove/disable other form elements) or will rely on RxJs for reactivity (meaning: auto-complete features or on-the-fly validation of user input using HTTP requests), then use reactive forms.
  • In all other scenarios, template-driven forms should be perfectly fine.

That’s it. A bonus for you: If you want to have custom validation of your form, use this tutorial to implement custom validation that works with both template-driven and reactive forms, so you’re not tied to a single option and can still change your mind later on.

Angular Accelerator Program

Since I started this newsletter at the beginning of the year, quite a few people have inquired about one-on-one coaching/training from me.

Several people have also asked for more preparation content for the Angular certification exams.

As a result, I’m about to launch the beta test of an Angular Accelerator program, and you can show your interest by filling out this form.

The program would combine weekly exercises and access to a Slack channel shared with other learners, me, and possibly other Angular experts, as well as live Q&A sessions and code reviews for each exercise.

On top of that, you would have access to all my video courses during that month of training. If you think this could interest you and want to try it as a beta tester, here is the form to fill out. You can also suggest ideas in that form.

Beta testers will be selected in the next couple of weeks based on their availability and time zone constraints, and the first cohort will likely be soon after that in July.

Thank you so much for your attention and participation.

How to pass multiple pieces of content from one component to another?

Yesterday, we saw that we could use content projection to pass an HTML template from one component to another. But what if we want to pass multiple different templates? We can use multi-slot content projection.

Here’s what we want to achieve:

In our reusable dialog component, we will have multiple ng-content elements. Each ng-content will have a specific query selecting a template to render:

These queries use the CSS selector syntax. In the above example, we’re using [], which means we are selecting HTML attribute names. As a result, our parent component will pass two distinct templates, one for the body and one for the footer, using the following syntax:

You can see an example of such code in action on Stackblitz.

Passing custom content to a component with content projection

If you’re creating a component library or working on components meant to be as generic and reusable as possible, then content projection should be a major part of your Angular toolkit.

Let’s take the example of a pop-up window/dialog component:

The main idea of content projection is that the parent component (most likely a container component) knows about the current use case of our reusable presentation component and can pass custom HTML to it. Such content is passed in the content section of the component, which is the body of the HTML element – what we have between the opening and the closing tag:

Angular projects that content into the template of the child component. We can set the destination of that projection by using an ng-content element in the template of the reusable component as follows:

Content projection is like cutting and pasting some content from one component to another. You can see the full code example here on Stackblitz.