Angular : Some good practices

This article is different from the precedent ones for it is aiming to give tips for common ways to better manage your projects in Angular. It supposes you have at least little working experience with Angular.

1.Styling your project :

This is about defining the architecture skeleton of your whole project. Okay , this sounds ambiguous , but I'll clear that up by tackling a common yet simple case.

We want to create a simple Website containing three routes : a Home page , a Services page and a Contact page. Inside those views , we may want to render different content blocks. So we may be talking about different components inside one single page. Generating components only is not a good practice in this scenario because we'll come up with our app folder having a long row of components folders.

A simple solution is creating modules for every page we want to render. And we may want to create some sub-modules inside our modules if we have too many components to render with different common themes. For now , we'll just create a very simple application without thinking about the different parts we want to render in each of our pages.

Let's begin by creating three modules inside our project.

> ng g m Home --routing 

> ng g m Services --routing 

> ng g m Contact --routing

The g command is a short syntax for generate and m for module . The routing flag is added to generate a routing-module file to manage our routes.

At the top level , you notice the following architecture. In each of the modules generated , taking the Home Module as an example , you can notice a Home Module file and a Routing Module file. The files' logic is almost the same as the App Module and the App Module routing. That is predictable since they are both modules !

Let's add a component in each module.

> ng g c home/HomePage 

> ng g c services/ServicesPage

> ng g c contact/ContactPage

Notice that I am starting the "page" noun with a capital letter , this will ensure generating a dash ( - ) between "home" and "page" and therefore have a clear component selector as follows : app-home-page .

Before generating each component , I am specifying the module the component must be nested into.

Now , what we want to do is make our modules available for the application . To be more concise , since we are working with routes , we want that our three modules routes are available for the whole application. This requires a two-step configuration. First , we want to set the path of each module route and make it available outside the module itself.

//home-routing.module.ts


import { HomePageComponent } from './home-page/home-page.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';


const routes: Routes = [{ path: '', component: HomePageComponent }]; // added this line


@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class HomeRoutingModule {}

Second , we want our App Module to recognize those modules since it is the bootstrapping module. So , we want to mention the HomeModule in the imports list since this property marks the other modules the AppModule depends upon.

// app.module.ts

//default import modules
import { HomeModule } from './home/home.module'; // added this 


@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, HomeModule],

 // added HomeModule in the imports property list

  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

I also did the same process with the two other modules and specified a route for each module's component . Now , let's visualize them by changing our app.component.html file.

<div class="ui container">

  <div class="ui three item menu">

    <a
      class="item"
      routerLink=""
      routerLinkActive="active"
      [routerLinkActiveOptions]="{ exact: true }"
      >Home</a
    >
    <a class="item" routerLink="services" routerLinkActive="active">Services</a>
    <a class="item" routerLink="contact" routerLinkActive="active"
      >Contact Me</a
    >
  </div>
</div>
<div class="ui center aligned segment">
  <router-outlet></router-outlet>
</div>

The classes I am using correspond to the Semantic-UI , a CSS + Javascript Framework. It is worth checking for those who want their styling to be quite unique and have trouble memorizing some classes since it uses human-readable langage for class names.

Semantic-UI-CSS installation and integration:

> npm i semantic-ui-css 

Then , in the styles.css file import the semantic style-sheet.

@import "semantic-ui-css/semantic.min.css";

Quick Note :

If you want to export different components inside a module without including a route , go to the specific module.ts file and add an exports property list , then include the Components you want to export to the other modules.

In a nutshell , we now have a clear organised project thanks to a modular architecture which splits our projects into big chunks of code under a unified theme for each. Remember that you can include sub-modules into the module itself if you need more organisation.

2.Lazy Loading :

This is a one hell of a feature I like. We're going to carry on with the example we worked above.

By default , when you go to a certain route , the Angular application would send a HTTP GET REQUEST to the Angular Development Server to fetch all modules available but only display the selected one. This is obviously time-loss operation , why would I have to load all the modules when I want to display a single one ?

We're going to do a little "fix" to this problem by tackling one module , that is the Contact module, then you can apply the same logic to the other modules.

First , begin by undoing the importation of Contact module in the app.module.ts file.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeModule } from './home/home.module';
import { ServicesModule } from './services/services.module';


@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, HomeModule, ServicesModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Now in the app-routing.module.ts file , modify the routes constant to look like follows.

const routes: Routes = [
  {
    path: 'contact',
    loadChildren: () =>
      import('./contact/contact.module').then((m) => m.ContactModule),
  },
];

What we are doing in here is that we are doing a dynamic import of the Contact Module when the contact path is triggered.

Important Note ! :

You have to modify the contact path into the contact-routing.module.ts file to look like follows.

const routes: Routes = [
  {
    path: '',
    component: ContactPageComponent,
  },
];

The reason behind that is that we are going to load the Contact Module when triggering the contact path as we mentioned in the app module routing file , so specifying the path again in the contact routing module would cause the need to access the contact/contact path to display the different components !

Go to the Network tab into the Developer tools and notice that when we go to the contact route, the Angular Development Server is only loading the specific module.

No alt text provided for this image

3.Reusable Components :

You might say , components are already reusable , you just need to use their selector in the appropriate page and we're done ! Okay , let me show you a good practice to make your components dynamically reusable.

We'll start by generating three components inside our Services Module.

> ng g c Services/ServiceOne


> ng g c Services/ServiceTwo

> ng g c Services/ServiceThree


Very creative for the components' names right ? Now, let's configure a route for each component inside the appropriate routing file that is the Services-routing.module.ts file.

// Only Update the routes constant and make sure to import the components
const routes: Routes = [
  {
    path: '',
    component: ServicePageComponent,
    children: [
      { path: 'service1', component: ServiceOneComponent },
      { path: 'service2', component: ServiceTwoComponent },
      { path: 'service3', component: ServiceThreeComponent },
    ],
  },
];

Now , in the service-page.component.html file , we want to display our components according to the specific route.

<div class="ui segment"><h1>My Services</h1></div>

<div class="ui divider"></div>

<div class="ui grid">

  <div class="four wide column">

    <div class="ui vertical fluid tabular menu">

      <a
        class="item"
        routerLink="service1"
        routerLinkActive="active"
        [routerLinkActiveOptions]="{ exact: true }"
      >
        Service One
      </a>

      <a class="item" routerLink="service2" routerLinkActive="active">
        Service Two
      </a>

      <a class="item" routerLink="service3" routerLinkActive="active">
        Service Three
      </a>

    </div>

  </div>

  <div class="twelve wide stretched column">
    <div class="ui segment">
      <router-outlet></router-outlet>
    </div>
  </div>
</div>

Now , let's say we want to use the same structure elsewhere , in the Home Module for example , and integrate the specific routes of different home components inside of it. You may think of a Parent-Child Component's relation and getting the desired variables from the parent Component , but there's a better solution. First of all , since we want to use this specific structure for more than a module , let's create a Shared Module where we can generate a similar Component , inside of which we create the desired component.

> ng g m Shared

> ng g c Shared/Menu

We don't add routing since we're going to be needing the structure only then use it in other components that we may want to render for a specific route.

First things first ! Let's make our Menu component available to the outside modules by adding the exports property to the Shared.module.ts file.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MenuComponent } from './menu/menu.component';


@NgModule({

  declarations: [MenuComponent],

  imports: [CommonModule],

  exports: [MenuComponent], // added this

})
export class SharedModule {}

Since we want to use this module's components into our Services Module , do no forget to import it into the services.module.ts file.

Now , let's change our menu.component.html file to look like this.

<div class="ui grid">

  <div class="four wide column">

    <div class="ui vertical fluid tabular menu">

      <ng-content select="[itemOne]"></ng-content>
      <ng-content select="[itemTwo]"></ng-content>
      <ng-content select="[itemThree]"></ng-content>

    </div>

  </div>

  <div class="twelve wide stretched column">
    <div class="ui segment"><ng-content></ng-content></div>
  </div>
</div>

We're using the ng-content directive. What this directive does is project a content inside another view. The reason behind the use of the select attribute on this directive is that it could be used only once. In order to be able to use more , we have to mark the added ng-content with the select attribute to project a different view from the precedent one. Putting the select value in square brackets [] means that we want to project content from the directive by adding the value as an attribute. Let's try to use that component into the services one to render the same view we were displaying.

Inside services-page.component.html file.

<div class="ui segment"><h1>My Services</h1></div>

<div class="ui divider"></div>

<app-menu>
  <a
    itemOne
    class="item"
    routerLink="service1"
    routerLinkActive="active"
    [routerLinkActiveOptions]="{ exact: true }"
  >
    Service One
  </a>
  <a itemTwo class="item" routerLink="service2" routerLinkActive="active">
    Service Two
  </a>
  <a itemThree class="item" routerLink="service3" routerLinkActive="active">
    Service Three
  </a>
  <router-outlet></router-outlet>
</app-menu>

As you can see , we are rendering the three different routes and adding the select value properties ( itemOne, itemTwo,itemThree) to the anchor tags. The ng-content which has no attribute will project the <router-outlet> content.

The select property adds flexibility to content display , since we are able to use the desired content we want. We could have to display two services , so we may delete one anchor tag.

That was a drop of the sea ! Angular contains much more practices to be aware of , and articles discussing other ones will be on my plans. See you soon !

To view or add a comment, sign in

More articles by Wael Messaoud

  • Angular 10 is out !

    It has been only 4 months since the 9th version has been out, and here we are again facing the next update. We will…

  • Manage your project with Webpack

    To start with , what is Webpack ? It is claimed to be a module bundler , but in my opinion it is more than that. But…

  • S.O.L.I.D Principles in a nutshell

    Software design is a heuristic process , thus those principles concerning the Oriented Object Programming are to be…

    1 Comment
  • Beware of Closures !

    This article's goal is to shed light upon tricky cases in Javascript. Do not skip if you don't know what a closure is ,…

  • Web Components outside Front-End Frameworks

    You may have encountered the term 'Component' while using front-End frameworks such as React or Angular. Their main…

    1 Comment

Others also viewed

Explore content categories