Custom form validation functions

Let’s continue our dive into Angular form validation capabilities. So far, we have seen how to display custom feedback to the user based on basic HTML validation features. Today, let’s see how to customize the validation itself.

The good news is that all we need is a function. That function takes a FormControl as a parameter and returns null if the value entered by the user is valid. If the value is invalid, we return a ValidationErrors object, any key/value object we want.

Here’s an example:

Pretty straightforward, right? If the zip code is wrong, we return an object with a custom error message. Otherwise, we return null.

Of course, we can validate more precisely by adding several different checks and specific error messages for each case:

Then to have a specific input use that validation function, we can pass it as a parameter to the FormControl constructor like so:

And then such FormControl gets bound to the proper input in our HTML template (this is the approach for reactive forms – we will cover a method that works for template-driven forms tomorrow). We can then add some error handling by using the errors property of our FormControl, which is going to have the ValidationErrors object returned from our validation function:

Now our form provides custom feedback using our custom validation function:

You can access the code for the above example on Stackblitz.

Implementing custom feedback to form validation with Angular

Yesterday, we saw that Angular uses six different CSS classes (actually, eight – I didn’t mention ng-pending, which is the temporary state when async validation is being performed, and ng-submitted, which applies to the form element only).

Today, let’s see how we can customize the feedback displayed to the user beyond CSS classes. The nice thing about Angular validation properties is that they’re not just available as CSS classes. They are also available as public properties on the ngModel and the ngForm directives used in our form.

We can access such properties using template reference variables to access the exported values of these directives as follows:

The above code would result in the following rendering:

Of course, displaying true or false is not very user-friendly. Instead, we can use *ngIf and make the experience a little more polished:

Which looks like this:

We can apply the same idea to the form element and decide to disable the submit button as long as the form is invalid:

Or we could even hide the button as long as the form is invalid:

You get the idea. As simple as those validation properties are, they enable many possible different customizations of how we display validation feedback and hints to the user.

You can play with my code example on Stackblitz.

Basic form validation with Angular

Validating user input in HTML forms can be a tedious task. In this new series, we’ll look at how Angular can help us implement painless form validation.

First, it’s essential to know that Angular relies primarily on native browser validation features that use modern HTML properties. For instance, if a form field has to be filled out, you can mark it as required using the required HTML attribute:

If the user input has to match a specific format, you can specify such format using the pattern attribute, which uses a regular expression syntax – here, a 5-digit number

Other available HTML validation attributes are min, max, minlength, maxlength. You can also set the input type to something more specific than text, such as email or tel for additional validation and capabilities. Here is the list of all possible input types.

Once you have specified your validation rules using such attributes, Angular is going to toggle some CSS classes on the corresponding HTML elements automatically: ng-valid when the entered value is valid, and ng-invalid when the entered value is invalid.

This means that all we have to do to provide visual feedback to the user is implementing such classes in our CSS stylesheets:

The above CSS classes result in the following styling of form inputs:

If we want to fine-tune the rendering of our form based on whether the user has already typed something or not, there are additional classes added by Angular for such purposes:

  • ng-pristine: true when the user has not changed the element value
  • ng-dirty: opposite of pristine — true when the user has altered the element value
  • ng-touched: true when the user has put focus on the element (say clicked on it) and then removed the focus from the element (clicked away from it)
  • ng-untouched: Opposite of touched — means the user hasn’t put focus on the element or hasn’t removed that focus yet.

Using combinations of these classes is powerful. For instance, here is how we could add the error styles only once the user has “touched” an input:

Which results in the following default rendering:

And then once the user has typed something and removed the focus from the element:

You can try a few live examples using the code from this Stackblitz repo. Tomorrow, we’ll see how to do more than just CSS styling using those validation properties.

Using Stackblitz as an Angular playground

The easiest way to get an Angular development environment up and running these days is to use Stackblitz. I mention Stackblitz today because a few readers have sent me links to Github repos that they use when they want to test some of the ideas of this newsletter.

While Github is perfectly fine, creating a new project with Angular CLI, downloading all dependencies then committing to Github can take a few minutes each time, while Stackblitz gets you started in just 2 seconds. All you have to do is head to https://stackblitz.com/ and click the Angular button:

Stackblitz is excellent for a few more reasons:

  1. If you create your free account on Stackblitz, you can save your projects for later and share them with others with just one URL. One click on the URL and the app is up and running; no installation nor hosting is needed! Your friend can then fork your project if needed.
  2. Stackblitz can be used to import (and sync with) Github repos, too. The URL stackblitz.com/github/{GITHUB_USERNAME}/{REPO_NAME} can be used to access a public repo on Stackblitz. For instance: stackblitz.com/github/alcfeoh/ng-weather
  3. Stackblitz has an Angular CLI-like tool accessible with a right click called “Angular generator”:

You can also use it for full-stack projects using Node.js (and possibly JSON server covered earlier!), which makes Stackblitz even more powerful. And it’s 100% free!

RxJs distinctUntilChanged operator

This week, our RxJs operator of choice is distinctUntilChanged, another of these few operators with a name that is explicit enough.

distinctUntilChanged ignores unchanged values that get emitted several times:

This operator is beneficial when using RxJs to filter out data based on filters selected by the end user in the UI. For instance, it’s a way to ensure that we only trigger a data update (such as an HTTP request) when the filters have changed.

A notable feature is that you can pass a custom comparison function as a parameter to determine how to compare those values. Otherwise, the operator uses === as a default comparison, which is acceptable for basic types but not for comparing objects unless you want to compare references.

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.

The power of Angular selectors

Yesterday, we saw how using directives instead of components can increase code reusability by not tying our code logic to a specific HTML template.

Now, if we want to write some code once and for all and make it work for all HTML elements in our app that match some specific conditions, we have another underused tool at our disposal: CSS selectors.

For instance, let’s say we want the isActive directive from our previous example to be applied to all buttons in our application. Of course, we could manually look for all buttons and add the isActive attribute to them, but that would be tedious and error-prone.

Or we could be more imaginative and change the selector of that directive so that it applies to all buttons and any other elements that have an isActive attribute:

With that implementation, all current (and future) buttons will have that directive applied to them. But what if we want to make any exceptions and disable the directive on some buttons? That’s how we could do it:

Then all we would need is to add the disableIsActive attribute to those buttons that don’t want the isActive directive:

My point here is that there are some creative use cases for CSS selectors, and those selectors are the same as those used for CSS styling, meaning that we can rely on classes, attributes, element names, or any combination of the above!

The Angular framework does precisely that in quite a few places. If you’ve ever wondered how forms get auto-magically handled by Angular, now you know the answer. The ngForm directive has a complex selector that would apply to all form elements by default:

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.

RxJs forkJoin operator

Our weekly RxJs operator is forkJoin. This operator can be applied to any number of Observables. When all these Observables complete, forkJoin emits the last value from each one of them.

A common use case for forkJoin is when we need to trigger several HTTP requests in parallel with the HttpClient then receive all of the responses at once in an array of responses:

The critical feature here is that those requests happen simultaneously, not one after the other (better performance), yet we receive the data when both have completed, which is convenient.

Another interesting syntax for forkJoin is to pass an object instead of an array as follows:

Here is a complete example of forkJoin in action.

As a reminder, my 2-hour RxJS workshop from ng-conf 2022 is also available on Youtube for free!

How to generate DTOs for data objects?

Yesterday, we saw how to use json2ts to generate type definitions for our Angular applications. In addition, we saw that interfaces are optimal for performance reasons. Yet, the caveat with interfaces is that they can’t act as a Data Transfer Object (DTO) on their own to change the data you’re dealing with, nor do they perform any runtime checks.

As a result, some people might prefer to use Quicktype over json2ts as it has more configuration options when generating code from a JSON string:

As you can see, those options enable additional capabilities, such as using union types instead of enums (as recommended earlier), throwing errors if an object you’re parsing doesn’t have the right shape, and even some DTO operations such as using camel case instead of underscore in property names.

Of course, you can tweak that generated code and add additional DTO rules as needed.

Quicktype also supports languages other than TypeScript, so you could use that same tool to generate the server-side types for your data in Java, C#, or Python, for instance.