Creating a dialog in two lines of code

The theme of our week so far is that we don’t always need to think just in terms of components. We saw that directives and CSS selectors can be powerful tools to keep in mind.

Today, I’m going to show how modern HTML and template reference variables can do a lot of work for us with very little code.

Dialogs and modal windows have been a pain to work with for a very long time on the web. Not anymore though.

Here are a few lines of code that makes it all work painlessly:

dialog is a modern addition to HTML with a simple API: show(), showModal(), close(). The above code creates a template reference variable #dialog to get access to the dialog element, and then we call dialog.showModal() to open a modal window. That’s it. No dependency is needed, no CSS trick to create an overlay, no component library, and no jQuery.

Here is a link to a fully working example and a slighter longer tutorial with styling information for HTML dialogs.

When to create a directive vs. a component?

Most Angular applications are composed of a majority of components and just a few directives if any. Today, I’d like to show you an example where a directive makes much more sense than a component.

Consider the following component template:

We have created a component tied to one single HTML element (button), and all the logic in that template is about changing attribute values (for the isActive class and the disabled attribute).

To achieve this, we needed three specialized inputs that resulted in a loss of reusability:

The above isn’t ideal because:

  • Our button can only display text, not any HTML (so no icons, for instance)
  • Our button assumes that its state always depends on saved and hasError, but what if we want to add a third variable to the mix for other use cases?

Let’s create a directive instead:

Which would be used like so:

This implementation is a lot better because:

  • It would work with any HTML element, not just buttons (assuming the element supports disabled properly)
  • The button can display anything, not just text
  • The criteria for isActive to be true depends on the use case and isn’t tied to just saved and hasError.

The point here is that using a directive in that scenario made our code more flexible, and as a result, more reusable. That’s why popular component libraries rely heavily on directives rather than components. Here’s an example from the Angular Material documentation:

You can see that mat-button is a directive, not a component. That way, it can be used with a button or an a tag. You can find the example code of this post on Stackblitz.

Think about this the next time you’re tempted to create a component with one or two lines of HTML in its template. Most likely, what you need instead is a directive.

Check out this tutorial for another example of a directive that makes perfect sense instead of using a component.

Change detection for Angular components

Angular comes with two component change detection strategies: default and onPush.

Default is used by default: Angular will check if your component needs to be refreshed every time something happens in the browser. Zone.js triggers such change detection by notifying Angular when a DOM event happens (someone clicked on a button) or a setTimeout completes, or an HTTP request completes.

In other words, any time a callback function runs in the browser, Angular will check if our components need to be re-rendered with new data.

With onPush, the change detection behavior changes. onPush indicates that our component only relies on inputs to display data (in other words – it’s a presentation component) and that DOM events or HTTP requests do not impact the HTML rendering of that component.

As a result, you can use onPush to improve the performance of your presentation components, which is another good reason to follow the presentation vs. container components approach covered yesterday. The official documentation here shows an in-depth dive into change detection strategies.

Container vs. Presentation Components

One of the fundamental concepts of component architecture in Angular applications is to find the right balance between container and presentation components.

Let’s define what those are:

  • Presentation components are reusable, simple pieces of UI. Think buttons, dialogs, cards, nav bars, etc.
  • Container components are the exact opposite: They’re not reusable. They’re tied to a specific use case. Those are usually entire screens or sub-screens, the app component, etc.

From a code standpoint, container components use services to interact with the back end. Such components know where to get the data using those services and then feed that data to their children using inputs, which are presentation components:

A simple way to identify those components is that presentation components only have inputs and outputs, no dependency injection. Container components have dependencies injected and most likely no inputs or outputs.

When to use container vs. presentation components?

Suppose you have components that are good candidates to become presentation components but are using services. In that case, you can most likely inject that service in its parent container and then pass the data to said component using an input. That way, your presentation component will be reusable in other places without being tied to a specific use case.

Of course, just like with any best practice, there are exceptions to consider. There are times when reusability makes sense and others when it does not. Do not force your components into one of these categories if it doesn’t make sense, but give it a try if it’s a quick win. Your application architecture (and possibly performance – stay tuned for more on that soon) will thank you later.

Template Reference Variables

Welcome to the very first edition of my daily Angular Newsletter! As promised, I’ll keep it nice and short.


Today’s topic is Template Reference variables. I usually call that feature “the hashtag syntax” because that’s how it’s used:

<input #phone placeholder="phone number" />Code language: HTML, XML (xml)

Here’s how I could use that reference variable to get the value of the input, for instance:

<button (click)="callPhone(phone.value)">Call</button>Code language: HTML, XML (xml)

phone refers to the input element with the #phone attribute created earlier. That’s the template reference variable.
These variables can be used instead of ngModel, for instance. Even better, they also work with components and directives!

For instance, the following template reference variable hello would have access to all public properties and methods of the HelloComponent:

<app-hello #hello ></app-hello>Code language: HTML, XML (xml)

For more information and examples, you can read another short blog post of mine here.