Address Book - Part 4 ( Multiple Components and use of @Input)

Let us continue from where we left in the previous post.

In this post we will
  1. Make our address book project modular.
  2. Having Input to our components
Our app.component.ts is doing everything, it is holding all the data displaying all the components. If  in future, we have to add a few more features to the address book module, chances are the entire file will become a mess. (Here we need to note that atleast our contact.html is a different file, having it in the same class would reduce code readability)

In Step 1, we will convert our existing code into a modular code.

We will create a contact.ts class, which will hold the class Contact.
export class Contact {
  
  name : String;
  contactNumber : Number;
  address : String;
  
}

Next, we will create a contact.dummy.ts which will hold the dummy data of the Contacts.
import { Contact } from './contact';

export var DUMMY_CONTACTS : Contact[] = [{
      name : "Jon Snow",
      contactNumber : 111,
      address : "North"
    },
    {
      name : "Cersie",
      contactNumber : 222,
      address : "Kings Landing"
    },
    {
      name : "Daenerys",
      contactNumber : 333,
      address : "Meereen"
    },
    {
      name : "Tyrion",
      contactNumber : 444,
      address : "Meereen"
    },
    ];

We will have to make required changes in app.component.ts to retrieve data from these two files. app.component.ts looks like this now
import { Component } from '@angular/core';
import { Contact } from './contact';
import { DUMMY_CONTACTS } from './contact.dummy';

@Component({
  selector: 'my-app',
  templateUrl: './contacts.html'
})
export class AppComponent { 
  
  selectedContact : Contact;

    title = "Address Book";
    
   contacts = DUMMY_CONTACTS;
    
    onSelection(contact : Contact) : void {
      this.selectedContact = contact;
    }
}

Run and you should get the earlier output:

Fig. 1

Rename app.component.ts as contacts.component.ts file. This will have the contact component data. We are moving towards dividing our app into smaller components. But this will be a step by step process.
import { Component } from '@angular/core';

import { Contact } from './contact';
import { DUMMY_CONTACTS } from './contact.dummy';

@Component({
  selector: 'contacts',
  templateUrl: './contacts.html',
})
export class ContactComponent{ 
  
  selectedContact : Contact;

  contacts : Contact[] = DUMMY_CONTACTS;
    
    onSelection(contact : Contact) : void {
      this.selectedContact = contact;
    }
}

Create app.component.ts as follows:
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<h1>{{title}}</h1>
             <contacts></contacts>
  `
})
export class AppComponent { 
  
    title = "Address Book";

}

Make changes in contacts.html
<ul class="contactList"
[class.selected]="contact === selectedContact"
>
    <li  *ngFor="let contact of contacts" (click)="onSelection(contact)">
<span > {{contact.name}}</span>
</li>
</ul>
<div *ngIf="selectedContact">
         <label>Name:</label>{{selectedContact.name}}
         <br>
         <label>Number:</label>{{selectedContact.contactNumber}}
         <br>
         <label>Address:</label>{{selectedContact.address}}
         <br>
         <input [(ngModel)]="selectedContact.name" type="text" placeholder="name">
</div>


Our app.module.ts will need to declare a new Component, the ContactComponent
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
import { FormsModule } from '@angular/forms';
import { ContactComponent } from './contact.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, ContactComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

Our output still looks like Fig. 1 above.

Let us add a new Component, the ContactDetailsComponent to display the detail data of each contact.
contact_details.component.ts
import {Contact} from './contact';

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

@Component({
    selector : 'contact-details',
    templateUrl : './contactDetails.html'
})
export class ContactDetailsComponent{
    
    @Input()
    selectedContact : Contact;
}

Here @Input decorator is used to tell the compiler that selectedContact is going to be an input for this component.
So when we call the contact-details component we will have to add a selectedContact attribute to the component.

<contact-details [selectedContact]="selectedContact"></contact-details>

Add a contactDetails.html file:

<div *ngIf="selectedContact">
         <label>Name:</label>{{selectedContact.name}}
         <br>
         <label>Number:</label>{{selectedContact.contactNumber}}
         <br>
         <label>Address:</label>{{selectedContact.address}}
         <br>
         <input [(ngModel)]="selectedContact.name" type="text" placeholder="name">
</div>


Make the following changes in the contact.html file:
<ul class="contactList"
[class.selected]="contact === selectedContact"
>
    <li  *ngFor="let contact of contacts" (click)="onSelection(contact)">
<span > {{contact.name}}</span>
</li>
</ul>
<contact-details [selectedContact]="selectedContact"></contact-details>

And add ContactDetailsComponent in app.module.ts
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';
import { FormsModule } from '@angular/forms';
import { ContactComponent } from './contact.component';
import { ContactDetailsComponent } from './contact_details.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, ContactComponent, ContactDetailsComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

And still the output looks like Fig.1



We have divided our app.component.ts into smaller components, which has increased readability and modularity (which is very useful when we build large and complex applications).  In spite of all this the output remains the same. Next post will be on styling the address book, making it more address book like.

Useful link: Angular Index

Comments

Popular posts from this blog

Writing your own ejabberd Module

npm ECONNREFUSED error

Conditional Flow - Spring Batch Part 6