Using attribute directives to wrap legacy components

Although they have wildly different approaches to web development sometimes we have to use jQuery and Angular together. jQuery embraces and extends the DOM API while Angular is trying to abstract it away as far as it is possible. But we often find a plugin we need to use that does not have a suitable Angular port. We want to limit the “damage” and generally want to contain the dependency so that we can continue following the Angular philosophy. Turns out there’s a great tool for the job: attribute directives.

An attribute directive is similar to a component. In fact the only difference between components and directives is that components have templates. An attribute directive can have lifecycle hooks and can do pretty much everything a component can, except having its own template and styles. The attribute part of its name refers to the fact that it can be accessed and used as a HTML attributes.

Built-in attribute directives include the hide, ngStyle, formControlName and lots of others. Fortunately we can define our own directives. Instead of using the @Component decorator we have to use the @Directive decorator, but the classes are similar. We’ll write one shortly that solves the jQuery dependency problem.

There’s a jQuery plugin for emojis which is quite mature and easy to use. It’s called emojionearea. It has everything we need, but sadly uses jQuery. Wouldn’t it be great if we could reuse it in our components wherever required, but leave the DOM access logic and jQuery out of our components? We can do that with an attribute directive. Here’s the code:

Let’s see what happens here. First we import jQuery and the emojionearea package. Then we define an attribute directive using the @Directive decorator. We add a selector, where the square brackets signify that it’s an attribute. As I mentioned, directives are almost the same as components. They share the same life cycle and most importantly, the same life cycle hooks. Our directive implements the AfterViewInit interface, so we can access the rendered DOM element.

We inject ElementRef to our directive’s constructor. It is used to access the element that our directive is attached to. In the ngAfterViewInit method we use the nativeElement property of the ElementRef to access the DOM element. We create a jQuery element from it and call the emojioneArea function. And that’s all, we can invoke the jQuery plugin on any DOM element from our components.

Here’s the example usage in one of our component templates:

As you can see, it’s really just an HTML attribute. One final word of advice. As we established when we were talking about the SharedModule, anything that’s supposed to be reusable should go in there. Since directives don’t contain business logic and are used to adorn our components they should go to the SharedModule.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.

Smart and Dumb Components in Angular

Today we’ll see how to organize our components so they are small, reusable, performant and only contain the necessary amount of logic. Let’s go through these bullet points.

Small components

Generally we want to solve a problem with the least amount of code that still can be understood. We don’t want to use hacks and tricks that are hard to figure out, but we want to make it as terse as possible. That’s the whole point of dividing our application to smaller components.

We’ll write our components with the Single Responsibility Principle in mind – a component will only have one responsibility, and one reason to change.

The Single Responsibility Principle (SRP) is a part of the SOLID principles. These principles are a set of best practices writing object-oriented applications. The SRP states that a class should encapsulate one and only one responsibility of the application, and that responsibility should be defined entirely in the class.

Reusable

We touched this subject when working with the SharedModule. A set of our components will eventually be reused in multiple places of our application. We need to make these components as dumb as possible – by removing any business logic from them, and by having a well-defined interface.

Performant

Our application needs to be responsive and fast. We’ll minimize the need for change detection and will have clear cases when it should be run on our components.

Smart components

There are two kinds of components. In React, they are called container and component. Angular has the same concept, but here they are called smart and dumb component, respectively.

A container or smart component is concerned with the how. It inject services, fetches data and passes it to its host of dumb components. Here’s the code and template of a smart component:

Notice the following:

  1. Our component injects a service.
  2. It also defines an Observable. Dumb components generally don’t define Observables. They deal with eagerly-available data.
  3. It has an ngOnInit hook, where we do some data fetching.
  4. Its template instantiates our dumb component (app-repo).

Dumb components

A dumb component’s task is to display data. It does not inject services. It only contains logic needed for displaying items (e.g. toggling an accordion, maintaining the currently selected item). A dumb component only communicates with its parent component, by using @Input and @Output properties.

They are commonly defined in the SharedModule. We do this to maximize reusability. It’s a great practice to start early on. I ran into this issue countless times when wanted to reuse a component in another module, only to find out that I’m causing circular dependencies.

Let’s see the code and template of a dumb component:

Key points:

  1. A dumb component is dumb. It only has an @Input property to accept data from outside.
  2. The input parameter is not an Observable. You’d open up yourself to serious subscription-management nightmares if you pass Observables to dumb components.
  3. I prefer using strongly-typed parameters, the Repo class represents a GitHub repository. It’s a good practice to get into, since you’ll get compile-time warnings and errors.
  4. The main task of the dumb component is to display data.
  5. We marked it with OnPush change detection. We do the same with smart components. We get into change detection a bit later.

Best practices

  • Write your smart components to fetch data and handle user communication (form submission, button clicks, etc.).
  • Place your smart components in the feature module where they are needed.
  • Write dumb components to display data. Do not put business logic into them.
  • Place dumb components in the SharedModule to avoid circular dependencies.
  • Dumb components can be promoted and smart components demoted. When this happens, move the component to its new place.
  • Litmus test: if you have a constructor your component is probably smart.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.

Angular CoreModule

In this article we’ll continue reviewing Angular module best practices. We’ve already covered how the SharedModule helps us eliminating 3rd party module listings and circular dependencies. We also reviewed the benefits of having a separate RoutingModule. Now we’ll check how to make true singleton services and organize them using the CoreModule.

As usual, there’s no CoreModule class shipping with Angular, we’re talking about best practices and conventions here.

What’s in a CoreModule?

The idea behind a CoreModule is that we put all global services in one place and import them to where they are required. The following services would be global:

  • Your HttpClient wrapper service: it’s a great idea to create a wrapper around it. You’d shield yourself from obsoletions and breaking changes. Consider that HttpClient is the second Angular Http service implementation. No guarantee there wouldn’t be a third.
  • Your Authentication service, if there is one. No point having multiple instances for multiple modules.
  • Your logging service.
  • A wrapper around the ngRx store – we’ll cover this much later.

Note that contrary to SharedModule, CoreModule does contain logic. You don’t need to keep it stupid, actual business rules can and should be written here.

Global singletons in Angular

Angular services are application-wide singletons, right? Well, the correct answer is that it depends. As long as you don’t use lazy-loading then technically they are. As soon as you start to lazy-load your modules it gets trickier.

If you have a theoretical BuzzService and inject it into your eagerly loaded AppComponent then you have one instance. It’ll be a singleton the same instance in all your other eagerly loaded components as well.

Let’s assume you have a lazy-loaded Settings and Dashboard module, both having components injecting BuzzService. When you load your SettingsModule you’ll get a second instance of BuzzService. The same happens when you load the DashboardModule – boom, a third instance. Depending on your use case this might or might not cause problems. Let’s see how to solve this and make our CoreModule services true singletons.

forRoot and providing services

Let’s see the code for a complete CoreModule and dissect it:

Until line 8 there’s nothing really new or noteworthy. On line 9, however we are defining a static method. Its name is forRoot, a convention you should follow too. This forRoot method returns an implementor of the ModuleWithProviders interface. This interface has two members, the type of the module called ngModule, and an array of providers.

As you can see in the example we use the same type as defined in the module. We list the providers here instead of the NgModule decorator. The last thing we need to do is import our CoreModule using the forRoot method in our AppModule. Note that you only use forRoot in AppModule and nowhere else. Here’s an example:

Notice that on line 10 we used CoreModule.forRoot instead of the “normal” way. This ensures that all our services provided by CoreModule (at least those which are listed in the forRoot method) are true global singletons, regardless of how they are loaded.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.

RoutingModule best practices in Angular7

ezgif.com-webp-to-jpg

In this post we’ll explore further Angular module best practices. Although we’ll talk about routing, the main focus of the article is the concept of a RoutingModule.

A custom RoutingModule

This best practice is “official”, the default Angular project template includes a file called app.routing.module.ts. Let’s see this file and figure out the benefits it offers:

Not much happens here – an empty route array is created. It is passed to the RouterModule.forRoot call, and RouterModule itself is exported.

Let’s focus on the latter first – in the previous article about the SharedModule we saw the benefits of importing and re-exporting common module dependencies. The same goes on here, our own RoutingModule imports the stock Angular RouterModule, works with it, then re-exports it. Our app module will only have to import the custom RoutingModule, no need to import RouterModule as well.

The point of a custom RoutingModule is to handle complicated routing. Sure, we could set up everything in our app module, but it tends to become rather bulky after a certain number of dependencies. So we create separate modules (Shared, Routing, Core and Features) to offload some initializing code, and make the process easier to follow.

Let’s see a real-world RoutingModule:

Notice that it’s not super complicated either. In fact, there’s only two extra lines of code, two Route objects representing two lazily-loaded feature modules. Don’t worry about lazy-loading yet, we’ll cover it in a later post. Point is, RoutingModules only focus on setting up your route hierarchy.

If you have a lazy-loaded app, or a smaller one using eager-loading this file will not get too long. If you’ve more complex needs (multiple layers of parent-child routes, a huge app) then you can separate your routing into smaller files. Either way, routing is stored in one place and will be simple to reason about.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.

 

SharedModule best practices in Angular7

In this post we’ll examine how to make our Angular modules future-proof. We’ll see what exactly should go into a SharedModule and how the rest of our application integrates with it.

A SharedModule is just a concept of structuring your application – there’s no built-in class in Angular for its functionality.

It saves you from constantly reorganizing your modules and components.

Here’s the deal: when you start a new Angular project your second step (after generating the template) is to add a new empty module. By convention we’ll call it SharedModule. You do exactly two things in it:

  1. Import and re-export dependencies for other modules (CommonModule, FormsModule, Angular Material or Primeng modules, etc.).
  2. Declare all dumb, reusable components, pipes and directives here and export them.

And here’s what you don’t do in your SharedModule:

  1. Declare services. They don’t really belong here. If they are application-wide singletons then they’re going in your CoreModule (which we’ll explore in a future post). If they are feature-specific then they’ll go to the feature module where you require them.
  2. Add business logic. Everything in your SharedModule is meant to be used by one or more of your feature modules. That means they must be dumb and generic as hell, so you don’t limit yourself when you need to use them.

If you’ve an existing project adhering to these conventions would be much harder. However it’s worth restructuring, because eventually you’d get circular dependencies.

Let’s see a super-straightforward SharedModule example:

As you can see we do the two things outlined above. First we import commonly used Angular modules required by other modules. Again, SharedModule is dumb as hell, it won’t really use most of these modules.

Then we declare our pipe (for the sake of brevity I only added one) and export it, so that other modules can work with it.

That’s all our SharedModule is and does.

Other modules and the SharedModule

All other modules in your application (RootModule, all your feature modules) can potentially import and depend on the SharedModule. The SharedModule typically won’t depend on your application modules, rather on 3rd party libs.

Recap

A SharedModule saves us from two types of Angular pains:

  • Maintaining a module dependency list in each and every module we have. When you add a new module dependency you just add it to your SharedModule and be done with it.
  • Having to worry and figure out circular dependencies between our own modules. By moving every pipe, dumb component and directive to one place we greatly eliminate potential circular dependencies.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.

Observables and the async pipe in Angular

In my previous post about Angular subscription management we concluded that the best solution is to use the async pipe. In this post we’ll see a common problem many people ran into with the async pipe.

An observable intro

Before we dive into the details it’s important to make some observations about observables. Observables are functions that tie together a source (e.g. an HTTP request, an event stream) and an observer (your run-of-the-mill Angular component).

The most important aspect of an observable is its temperature. It can either be cold or hot. A cold observable creates its own source, while a hot observable wraps around one.

Cold observables are creating their sources

Consider the following code:

Notice how the observable is creating and dispatching the XMLHTTPRequest. Every subscriber will get a different request, resulting in multiple calls. We’ll review hot observables and then see how to avoid these issues.

Hot observables are wrapping around an existing source

Hot observables are great in the sense that they can share their results with multiple subscribers (they are multicast). However since they are not owning their source they cannot be lazy. Let’s review the same code fragment with a hot observable:

The hot observable is stored in the subject variable. Note that it wraps around our XMLHTTPRequest, which is completely independent from it. The request will always be sent with or without any subscribers.

Note that this is just for presentational purposes. There are better ways to connect subjects with observables. Also, you’d rarely send raw XMLHTTPRequests in Angular, you’d use the built-in HttpClient instead.

Smart usage of the async pipe

After some theoretical background, let’s see how this affects us and our components.

Look at the below component and template code:

callResult$ is a cold observable and we’re in big trouble. The *ngFor directive will trigger one execution, then the expression with the length below will trigger another.

We can fix this with a hot observable like this:

But this is more code, and we don’t like to write and maintain more code. Let’s try a different approach. A better solution would be this:

Using the async pipe with the async as syntax we can define a template variable. It’s called result in our case. The template then can reuse this variable without triggering the observable multiple times. We made our template code agnostic on the temperature of our observable, yayy!

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practicesFollow this link to the relevant part of the code.

RXJS subscription management in Angular

If you’re reading this then you’re probably familiar with the fact that Angular uses RxJS and embraces the reactive paradigm. You might be familiar that RxJS is based on the Observable class. Let’s recap what this means.
 
To extract any information from an Observable we need to subscribe to it. A subscription is a bunch of optional callback functions. We can define a success, an error function and a completed function, all of them optional. When an Observable emits, RxJS invokes the proper callback function.
 
Subscriptions aren’t free though, you’re required to tell RxJS when you’re done with them. It’s pretty easy, you need to invoke their unsubscribe function. The problem is – when and how to do that?

Not unsubscribing

 The easiest – and worst – solution is to ignore the problem. Subscribe to an Observable and leave it at that. When Angular destroys your component the open subscription will simply leak it.
 
Your subscriptions are holding a reference to the hosting component. If you don’t unsubscribe then you’ll create a memory leak with your whole component.

Manual subscription management

Let’s take a step in the right direction. Usually you’ll set up your observables in the ngOnInit lifecycle hook. There’s a corresponding hook when your component is destroyed, called ngOnDestroy. By simply storing all your subscriptions as members of your component class you can just call unsubscribe on all of them in the destroy hook.
 
 
This is a solution to the problem, but not a great one. For simple components it might work. But when you are adding more subscriptions later, you might forget to unsubscribe from them. And let’s face it, we just copying and pasting the code lines in cases like this, and will forget to change the variable name eventually.

Semi-automatic management with takeUntil

 We can harness the power of hot observables, aka Subjects. The logic is the same as when you’re using manual management. The difference is that you create a subject. In every observable subscription you pipe your subject through the takeUntil operator.
 
You also create an ngOnDestroy hook and complete your subject there. This will unsubscribe from your observables.
 
 
There’s a slight catch though. Order matters when piping operators, and you generally want to put takeUntil to the very end. The actual reasons are beyond the scope of this post, refer to this article on Angular in Depth.

Using the async pipe

 My personal favourite is to delegate the subscription management to Angular. This results in much less code and very straightforward components. Angular has the built-in async pipe for consuming observables. You’d use them in your component template.
 
 
Notice how all the subscription boilerplate code is gone. That’s a great thing, we need to maintain less code!
 
Also, when your component is destroyed Angular automatically unsubscribes from your observables. Though there are some caveats you should look out for.
 
If you use an async pipe multiple times on the same observable you’d get a different subscription. This could lead to multiple API calls. Fixing this will be the subject – pun intended – of my next post.

Source code

I’m maintaining and developing a repo on GitHub. It contains Angular7 best practices. Follow this link to the relevant part of the code.