Modularize Angular Application Angular 9

How to Modularize Angular Application – Angular 9 ?

This tutorial guides you on how to modularize angular application by splitting angular app in to components. Let’s learn how to modularize angular application with an example.

Modularize Angular Application – Angular 9

If your Angular application is all running in one component, let’s say App Component. And if all the code is written in the app component, then it is recommended to split the logic and move to a different component. Note, it is not good to have all the logic in App Component alone.

Splitting up logic in to different component will also enable you to reuse the component in different places.

Let’s consider the following example, in which all the code is written in App Component.

app.component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12">
      <p>Add Item Name and Description!</p>
      <label>Item Name</label>
      <input type="text" class="form-control" [(ngModel)]="newItemName">
      <label>Item Description</label>
      <input type="text" class="form-control" [(ngModel)]="newItemDesc">
      <br>
      <button
        class="btn btn-primary"
        (click)="onAddItem()">Add Item</button>
      <button
        class="btn btn-primary"
        (click)="onAddItemSpec()">Add Item Specifications</button>
    </div>
  </div>
  <hr>
  <div class="row">
    <div class="col-xs-12">
      <div
        class="panel panel-default"
        *ngFor="let elem of itemElems">
        <div class="panel-heading">{{ elem.title }}</div>
        <div class="panel-body">
          <p>
            <strong *ngIf="elem.type === 'item'" style="color: orange">{{ elem.desc }}</strong>
            <em *ngIf="elem.type === 'spec'">{{ elem.spec }}</em>
          </p>
        </div>
      </div>
    </div>
  </div>
</div>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  itemElems = [];
  newItemName = '';
  newItemDesc = '';
  newItemSpec = '';

  onAddItem() {
    this.itemElems.push({
      type: 'item',
      title: this.newItemName,
      desc: this.newItemDesc
    });
  }

  onAddItemSpec() {
    this.itemElems.push({
      type: 'spec',     
      title: 'Specifications',
      spec: 'Specifications of ' + this.newItemName,
    });
  }
}

When you run the above angular code you would see the following output.

Modularize Angular Application Angular 9

How to split app component to modularize our angular application?

We could create a separate component for section where we enter item name and item description with buttons. Let’s call it as “create-item” component.

And of course we can also create component for individual items that can be created. let’s call it as “item-element” component. With this modularization we will have much leaner app component HTML file. And we will be able modularize our business logic better so that reusability can be improved.

You can use angular CLI or do it manually to create individual components. Let’s create “create-item” component using ng command as shown below.

>ng g c create-item

CREATE src/app/create-item/create-item.component.html (26 bytes)
CREATE src/app/create-item/create-item.component.spec.ts (657 bytes)
CREATE src/app/create-item/create-item.component.ts (294 bytes)
CREATE src/app/create-item/create-item.component.css (0 bytes)
UPDATE src/app/app.module.ts (479 bytes)

Then let’s create “item-element” component as shown below.

>ng g c item-element

CREATE src/app/item-element/item-element.component.html (27 bytes)
CREATE src/app/item-element/item-element.component.spec.ts (664 bytes)
CREATE src/app/item-element/item-element.component.ts (298 bytes)
CREATE src/app/item-element/item-element.component.css (0 bytes)
UPDATE src/app/app.module.ts (583 bytes)

With this you will get two new folders under app component. Now let’ start modifying app component and move the logic to the new components that are created as shown below.

After modifications your App component should looks like below.

app.component.html

Now, we have much cleaner app component code as shown below. Basically, we have moved the template code related to iteam name, item description and buttons to create-item.component.html template and made necessary changes to bind custom events “itemAdded” and “itemSpecAdded” amd custom property “itemElement”.

<div class="container">
  <app-create-item (itemAdded)="onItemAdded($event)"
                   (itemSpecAdded)="onItemSpecAdded($event)"></app-create-item>
  <hr>
  <div class="row">
    <div class="col-xs-12">
      <app-item-element *ngFor="let elem of itemElems"
                        [itemElement] = "elem"></app-item-element>
    </div>
  </div>
</div>

app.component.ts

Here we hade moved the methods onAddItem() and onAddItemSpec() to “create-item.component.ts” typescript file and created new methods onItemAdded() and onItemSpecAdded() to handle custom events.

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  itemElems = [{type: 'item', title:'Google Pixel', desc:'Android phone by Google', spec:''},
  {type: 'spec', title:'Specifications', desc:'', spec:"Specifications of Google Pixel"}];

  onItemAdded(itemData:{itemTitle: string, itemDesc: string}) {
    this.itemElems.push({
      type: 'item',
      title: itemData.itemTitle,
      desc: itemData.itemDesc,
      spec:''
    });
  }

  onItemSpecAdded(itemSpecData:{itemTitle: string, itemSpec: string}) {
    this.itemElems.push({
      type: 'spec',     
      //title: itemSpecData.itemTitle,
      title: 'Specifications',
      desc:'',
      //spec: itemSpecData.itemTitle
      spec: 'Specifications of '+ itemSpecData.itemTitle
    });
  }
  
}

And the template and typescript files of “create-component” should have the following code.

create-item.component.html

<div class="row">
    <div class="col-xs-12">
      <p>Create Items and Specifications!</p>
      <label>Item Name</label>
      <input type="text" class="form-control" [(ngModel)]="newItemName">
      <label>Item Description</label>
      <input type="text" class="form-control" [(ngModel)]="newItemDesc">
      <br>
      <button
        class="btn btn-primary"
        (click)="onAddItem()">Add Item</button>
      <button
        class="btn btn-primary"
        (click)="onAddItemSpec()">Add Item Specifications</button>
    </div>
  </div>

create-item.component.ts

Create two new properties “itemAdded” and “itemSpecAdded” and use @Output decorator.  And make sure that you use EventEmitter along with @Output decorator so that both properties can emit events as shown below. And methods onAddItem() and onAddItemSpec()  are moved from app component with the following logic.

import { Component, OnInit, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-create-item',
  templateUrl: './create-item.component.html',
  styleUrls: ['./create-item.component.css']
})
export class CreateItemComponent implements OnInit {

  @Output() itemAdded = new EventEmitter<{itemTitle: string, itemDesc: string}>();
  @Output() itemSpecAdded = new EventEmitter<{itemTitle: string, itemSpec: string}>();

  newItemName = '';
  newItemDesc = '';
  newItemSpec = '';

  constructor() { }

  ngOnInit(): void {
  }

  onAddItem() {
    this.itemAdded.emit({
        itemTitle: this.newItemName, 
        itemDesc: this.newItemDesc
    });
  }

  onAddItemSpec() {
    this.itemSpecAdded.emit({
      itemTitle: this.newItemName, 
      itemSpec: this.newItemSpec
    });
  }

}

The “item-element” component template and typescript files should have the following logic.

item-element.component.html

Here we had moved individual item element specific logic from app.component.html.

<div
class="panel panel-default">
<div class="panel-heading">{{ itemElem.title }}</div>
<div class="panel-body">
  <p>
    <strong *ngIf="itemElem.type === 'item'" style="color: orange">{{ itemElem.desc }}</strong>
    <em *ngIf="itemElem.type === 'spec'">{{ itemElem.spec }}</em>
  </p>
</div>
</div>

item-element.component.ts

Create custom property and expose “itemElem” property to other components using @Input decorator and define the type as shown below. This represents an item element.

import { Component, Input, OnInit } from '@angular/core';

@Component({
  selector: 'app-item-element',
  templateUrl: './item-element.component.html',
  styleUrls: ['./item-element.component.css']
})
export class ItemElementComponent implements OnInit {

  @Input('itemElement') itemElem : {type: string, title: string, desc: string, spec: string};

  constructor() { }

  ngOnInit(): void {
  }

}

Finally, you had modularized angular application – Angular 9 code. Therefore, you had split single app component to multiple components. And each component could communicate each other which is more important when you modularize angular application.

That’s it. When you run the modified modularized angular application, you should be able to see the same output.

Hope it helped 🙂

Also See:

References:

Leave a Reply

avatar
  Subscribe  
Notify of