Angular Custom Pipes: Best practices

This article is not an in-depth guide on how to create complex pipes, but rather some tips and best practices guidelines on how to create custom pipes and make them reusable.

Pipes are an incredibly useful and clean way to transform data in the template in Angular. For doing this, Angular provides us with 2 types of pipes: Built-in Pipes and Custom Pipes.


Built-in Pipes

Built-in Pipes are easy to use, just a small example:

These built-in Pipes come with Angular framework and are just ready to use, no configuration is really needed. For a list and documentation of the built-in pipes just click here!


Custom pipes

Now, the most interesting feature of Angular’s pipes is the fact that we can customize pipes, therefore, create our own pipes. This opens a whole new world and allows us to transform data right on the HTML template following any logic that suits us.

This is achieved with the Custom Pipes.

A simple example of a Custom Pipe is the Capitalize pipe, it’s usually one of the first pipes created on any project (We still don’t know why Angular team doesn’t include it within the built-in pipes).

Some best practices for creating pipes are:

  • Use camelCase for the name of the pipe (the name in template, not the Class name), is what Angular team uses and is great for maintaining consistency. Example: ‘capitalizeWord’.
  • Always try to use Pure Pipes (all pipes are pure by default). Impure pipes have a huge negative impact on the performance. For more information check the Angular’s Guide.
  • No filtering and ordering pipes. Angular doesn’t come with them and you shouldn’t create an impure pipe to do these things, you should rather handle that in the component’s logic. For more information check the Guide.
  • Create it in a shared folder. All utility and stuff that will be needed all around the app should be created in a shared folder, such as: Pipes, Directives, Services, Models, etc.

This pipe takes the first letter and sets it to uppercase. In order to use this pipe, let’s say in AppComponent, we could use it in the following way:

AppModule:

In AppComponent we can just do the following and it will work:

<h1>
Hello {{ 'world' | capitalize }}! // Output is: World
</h1>

Making the Custom Pipe globally accessible

Ok, now we created a Custom Pipe that is working, but, is this really how we want to be working? Is this an ideal file structure? The answer is NO.

This approach has a HUGE problem. This Pipe can ONLY be used by components declared in AppModule.

We should have a file structure similar to this one by now:

    app.component.css
app.component.html
app.component.spec.ts
app.component.ts
app.module.ts
- shared
capitalized.pipe.ts

Now we want to create a new component, let’s say a Login Component, so we’ll modify our file structure to look something like this:

    app.component.css
app.component.html
app.component.spec.ts
app.component.ts
app.module.ts
- login
login.component.css
login.component.html
login.component.spec.ts
login.component.ts
login.module.ts
login.service.ts
- shared
capitalized.pipe.ts

We could assume that our Pipe works like a service, we declared it in AppModule, therefore it should be available in the rest of the App, right?

Wrong, and the reason is simple: In order to use Components, Directives and Pipes in a Module they must have been declared in THAT Module.

If we try to use our CapitalizePipe in a component that is declared in another Module we’ll have the following error:

Uncaught Error: Template parse errors: The pipe ‘capitalize’ could not be found

But don’t worry, the trick is that Modules can be imported as many times as you want or need.

So, the best way to create a reusable Custom Pipe is to create a SharedModule where it gets declared and exported, and then import that module all over your App.

Let’s have a look at how our SharedModule should look like:

And now we just import SharedModule in our LoginModule:

And now it will just work fine! Just remember not only to declare the pipe but also to export it.

Our file structure now should look something like this:

- app
app.component.css
app.component.html
app.component.spec.ts
app.component.ts
app.module.ts
- login
login.component.css
login.component.html
login.component.spec.ts
login.component.ts
login.module.ts
- shared
capitalized.pipe.ts
shared.module.ts

We achieved something great! We created a useful Custom Pipe that can easily be used in any part of the App, we’ll just need to import SharedModule and we‘ll be done. Congratulations!

From here on, we can change several things and are totally up to the developer’s personal taste, some of these thing are:

  • Create an CustomPipesModule, CustomDirectivesModule and import them separately instead of all together
  • Create several folders inside shared, such as: pipes, directives, helpers, models, etc.

Summary

  • If it already exists a built-in pipe that does what you want to do, use that one. (I’m amazed of how many people tend to reinvent the wheel)
  • Use intuitive and useful names for the pipe (remember you’re probably not the only one looking at the code!)
  • Create all your pipes within a shared folder and export them in the same Module so that they can be reusable throughout the whole application.

Thank you for reading!

It’s my first article here so if you have any useful tips please let me know!

If you have any questions don’t hesitate to leave a comment! 😉