Best practices for using visibility modifiers

Yesterday, we talked about Typescript visibility modifiers in the context of Angular classes. Today, I want to focus on best practices and common scenarios that involve such visibility modifiers.

First, it’s very common to have Angular services that use RxJs Subjects. Subjects are somewhat dangerous because they can be used to emit data to all subscribers. As a result, it makes sense to “hide” a subject by making it private and then expose an Observable out of it as follows:

Note that we don’t need to make data$ public, because any field that isn’t private or protected is public by default. Using readonly enforces that other components/services cannot assign a new value to data$. As a result, the above code is safe: The business logic that decides when and how to emit data is “hidden” in our service (where it belongs), and yet the rest of the application can be notified when the data changes without being able to break that process by accident.

Of course, the same idea applies to Signals (see my best practices for Signals)

Another option suggested in that post is to define a getter method that returns the read-only object:

This is equivalent to using readonly. The value can’t be changed because we define a getter and no setter.

Let’s complete our best practices list from yesterday:

  1. Make every member private by default
  2. If the member is needed in the template of a component, make it protected
  3. If the member is meant to be fully public, go with public
  4. If the member should be accessible but not modifiable, use readonly or a single getter with no setter

Typescript visibility modifiers

Angular is mostly about Typescript classes, and Typescript classes have modifiers that alter the visibility of class members: public, protected, private, and readonly. Here is what you need to know about them.

Everything is public by default

If you don’t use a modifier on a class member, it is public by default. Any other class can see and use that member and change its value:

private means that the member isn’t visible outside of the class (including a component’s HTML template)

private is a way to enforce that other classes cannot access a member of your class. Used in a component, this indicates that we do not want that property to be used in the component’s HTML template. In a service, this suggests that we don’t want other components/services to see that member:

protected is in-between public and private. It makes the member accessible in a component’s template without making it fully public.

In the following example, our component property date is invisible from other Angular code in our app, but our HTML template can use it:

Best practice – My recommendation

If you want to stick to simple rules that make sense and are the safest, here’s what you can do:

  1. Make every member private by default
  2. If the member is needed in the template of a component, make it protected
  3. If the member is meant to be fully public, go with public

Tomorrow, I’ll add a couple more suggestions by introducing the readonly modifier. Stay tuned!

ngSwitch directive

The ngSwitch directive is a good alternative to ngIf if you have to handle more than two scenarios.

It works similarly to a switch statement in traditional programming languages, allowing you to define a set of cases and associate each case with a specific template block to be rendered. For instance:

One of my favorite use cases is for basic pagination in a component (or an image carousel, for instance) where clicking on navigation buttons changes a value that triggers a different “case”:

Clicking on the buttons changes the value of page and displays a different template. Applying this to components instead of HTML elements is especially powerful. For instance: <app-hello *ngSwitchCase="3"></app-hello>

You can see an example in action on Stackblitz here.

RxJs Timer for recurring tasks

You’re probably familiar with setTimeout (to run some code after a given timeout) and setInterval (to run some code at a given time interval). Both are “native” Javascript functions and can be used with Angular.

That said, recurring code execution is asynchronous, and asynchronous work is often done with RxJs in Angular apps. As a result, let’s talk about a 100% RxJs way to replace setTimeout and setInterval.

The RxJS timer operator creates an observable that emits a value after a specified delay. The delay can be specified in milliseconds or as a Date object.

The following code creates an observable that emits a value (0) after one second:

If we want timer to emit immediately and then keep emitting at a given interval, we can do the following:

This would emit 0 immediately, then 1 five seconds later, 2 ten seconds later, etc. Most of the time, we don’t care about the emitted number. We want to turn that Observable into another one (like an HTTP request, for instance) using our good friend switchMap:

What’s the benefit of using timer in such scenarios? We get automatic unsubscriptions if we use the async pipe or the takeUntilDestroyed operator.

Here is a tutorial for a concrete example of how to do HTTP polling with Angular and the timer operator.

How to create custom directives?

I’ve touched on when it makes sense to create custom directives , how to use bindings in directives, and how to get creative with Angular selectors.

Today, let’s tackle how to create custom directives. The first thing to do is to use the Angular CLI:

ng generate directive [name]

or ng g d [name]

It’s also possible to generate standalone directives with the --standalone option:

ng generate directive [name] --standalone

Once you’ve done that, you end up with an empty class to implement:

At that point, it’s important to remember that a directive is just like a component. The only difference is that a directive doesn’t have an HTML template. As a result, we can still use @Input(), @Output(), and all sorts of bindings and listeners.

As a result, your directive will manipulate HTML attributes and events on its host element. Here is a typical example of a custom directive that sets a credit card logo image based on a credit card number:

Its source code looks like this:

As you can see, we use an @Input() to receive the cardNumber and a host binding to change the value of the src attribute. You can find a step-by-step tutorial that explains the above code in more detail here.

Localized pricing now available for all courses and exams

Subscribers of this newsletter are located on all continents worldwide. Still, I’m based in one of the most expensive states (California) of one of the most expensive countries (USA) in the world, which means that sometimes, people complain about the prices of my services.

Good news! I decided to apply purchase parity pricing (PPP) on all my courses and certification exams, which also applies to the upcoming Angular Accelerator program.

If you live in an eligible country and go to the purchase page of any of those courses, a banner will appear with a coupon code that gives you a discount based on your country’s economic situation.

Of course, I can also make further exceptions on a case-by-case basis, so feel free to email me if you’re in a challenging situation and need financial assistance, or if the banner doesn’t show up for you.

RxJs trick: Emitting from an Observable into a Subject

Using a Subject to emit data is something we do a lot in Angular applications, and more often than not, what we try to emit is the result of an HTTP request, such as:

While the above works perfectly well, it’s important to know that the subscribe method of an Observable takes either a function as a parameter (which is what I’ve done in the previous example) or an object that implements the Observer interface. We touched on that interface earlier to illustrate exciting things we could do with the tap operator.

The thing is that Subjects implement that interface, so we can simplify our earlier code into:

This isn’t just a syntax improvement, as writing less functions results in better overall Javascript performance. Less code to ship = less code to download = less code to interpret and store in memory for the browser = faster user experience. You can see a code example here on Stackblitz.

How to create custom form controls with Angular?

When working with lots of forms, you’ll likely use similar controls repeatedly: A country selection dropdown, a state selection dropdown, a date-range picker with specific constraints, etc.

Instead of duplicating our code, which is never a good idea, Angular allows us to create custom form controls that integrate with Angular’s form validation mechanism.

This feature requires our custom control component to implement an interface called ControlValueAccessor that has the following methods:

I have a detailed tutorial and code example if you want to dive deeper into that topic.

It’s also worth noting that you don’t have to start from scratch when implementing a control value accessor. Angular has a DefaultValueAccessor directive (the one used by FormControl, NgModel, etc., in Angular forms) that can be invoked with the selector ngDefaultControl, and there are a few more options available, such as the SelectControlValueAccessor.

How to run code in an injection context?

Yesterday, I introduced an injection context, and we saw a few locations where we could inject dependencies. This can be limiting in scenarios where we call a method that creates and returns an Observable outside of an injection context, as we can’t always initialize observables in a constructor. Does that mean we cannot use the takeUntilDestroyed operator in those scenarios?

No, because we can store our injector for later use using the following approach:

The key is to use the runInInjectionContext function and pass the injector as a parameter.

For the takeUntilDestroyed operator, we can inject a DestroyRef in our injection context and then use it as a parameter whenever we need that operator:

Problem solved! We can use all these tools from the framework in any place we want, thanks to EnvironmentInjector and DestroyRef.