38
loading...
This website collects cookies to deliver better user experience
Smart components
: Keep all functions and are responsible for getting all the information shown on dumb components
. They are also called application-level-components
, container components
or controllers
.
Dumb components
: Their only responsability is to show information or execute functions from the smart component
. Also called presentation components
or pure components
.
ng new angular-hierarchy-components --style=scss --routing=true --skipTests=true
app.component
to later refactor it using smart
and dumb
components.app.component.ts
and app.component.html
:app.component.ts
:export class AppComponent {
title = 'angular-hierarchy-components';
brands: string[] = [`Mercedes`, `Ferrari`, `Porsche`, `Volvo`, `Saab`];
remove(id: number) {
this.brands.splice(id, 1);
}
new(brand) {
this.brands.push(brand.value);
}
}
remove
to remove brands from the list and new
to add new brands to the list.app.component.html
:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div class="container">
<div class="container__form">
<form #root="ngForm" (ngSubmit)="new(newBrand)">
<input type="text" name="brand" #newBrand />
<button type="submit" #sendButton>Add</button>
</form>
</div>
<div class="container__brand" *ngFor="let brand of brands; let i = index">
<div class="container__brand__name">
{{ brand }}
</div>
<div class="container__brand__button">
<input type="button" (click)="remove(i)" value="x" />
</div>
</div>
</div>
</body>
</html>
new
function that adds a new brand to the brands list and a ngFor
that prints each brand name and a button to execute the remove
function that removes the brand from the list.There’s no way to reuse the code that prints out the brand list and the button to remove the brands name. If I want to implement this functionality on the same app but for clothing brands I will have to repeat the code.
If the app keeps growing I will have to stack all the functionalities on the app.component.ts
so after adding each functionality the app turns out to be more and more difficult to maintain.
smart
and dumb
components.smart component
that will contain:new
method to add new brands to the list.remove
method that removes brands from the list.smart
and dumb
components.smart component
that will contain:new
method to add new brands to the list.remove
method that removes brands from the list.ng generate component smartComponent
smart components
to use as pages so I name it like blogPage
or something like that but for this case I will just call it smartComponent
.app.component.ts
to smart-component.ts
so now it will look like this:export class SmartComponentComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
brands: string[] = [`Mercedes`, `Ferrari`, `Porsche`, `Volvo`, `Saab`];
remove(id: number) {
this.brands.splice(id, 1);
}
new(brand: string) {
this.brands.push(brand);
}
}
smart-component.component.html
and set the layout to render the dumb components
and I will have to create two dumb components
:<div class="container">
<div class="container__form">
<!-- here goes the brands form -->
</div>
<div class="container__brand" *ngFor="let brand of brands; let i = index">
<!-- Here goes the brands name component -->
</div>
</div>
dumb components
.list-element
components. This component will render one brand’s name and a button close to it to remove the brand from the list.ng generate component listElement
list-element.component.ts
I have to define:smart component
? Yes. The smart component
will hold all the information and functions but will pass the brand’s name and array position to the dumb component
in our case list-element
using angular
input binding
.Input
from @angular/core
on the list-element.component.ts
component:import { Component, Input, OnInit } from '@angular/core';
@Import()
decorator to define the values we are expecting:@Input() brand: string;
@Input() id: number;
list-element.component.ts
:<div class="container__brand">
<div class="container__brand__name">
{{ brand }}
</div>
<div class="container__brand__button">
<input type="button" value="x" />
</div>
</div>
smart component
.remove
function we defined on the smart component
from the list-element component
we have to use another functionality from angular
called Output
in conjunction with EventEmitter
. This will allow us to “emit” events to the smart component
in order to execute methods.Output
and EventEmitter
to our import:import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
@Output
decorator and the EventEmitter
:@Output() removeEvent = new EventEmitter<number>();
list-element.component.ts
I will define a method that will trigger the EventEmitter
when the user clicks on the remove button:removeBrand(id: number) {
this.removeEvent.emit(id);
}
smart component
so the remove
method on the smart component
is executed and the brand is removed from the list.element-list.component.html
we have to implement this method when the user clicks the remove button:<div class="container__brand">
<div class="container__brand__name">
{{ brand }}
</div>
<div class="container__brand__button">
<input type="button" (click)="removeBrand(id)" value="x" />
</div>
</div>
smart component
with the element-list component
. The smart component
will be responsible to loop the brands list and use the list-element
component to render the brands name and a button to remove. On the smart-component.html
we will use the element-list
component and pass to it the brands name and array position:<div class="container">
<div class="container__form">
<!-- here goes the new brand form component -->
</div>
<div class="container__brand" *ngFor="let brand of brands; let i = index">
<app-list-element
[brand]="brand"
[id]="i"
(removeEvent)="remove($event)"
></app-list-element>
</div>
</div>
app-list-element
component tag. We can see we are using 3 parameters/attributes:brand
and id
uses []
and events uses ()
it’s the same we do in Angular when we use data-binding
or any other event like click
:ng generate component newBrand
emit
the new brand’s name to the smart component
so I will start by importing Output
and EventEmitter
to emit the new value:import { Component, EventEmitter, OnInit, Output } from '@angular/core';
@Output
decorator:@Output() newEvent = new EventEmitter<string>();
emit
the new brand’s name to the smart component
:new(brand: { value: string; }) {
this.newEvent.emit(brand.value);
}
new-brand.component.html
I add the form and set it to execute the new
method when submit:<form #newBrand="ngForm" (ngSubmit)="new(newBrandInput)">
<input type="text" name="brand" #newBrandInput />
<button type="submit" #sendButton>Add</button>
</form>
smart component
to the new-brand component
on the smart-component.component.html
:<div class="container">
<div class="container__form">
<app-new-brand (newEvent)="new($event)"></app-new-brand>
</div>
<div class="container__brand" *ngFor="let brand of brands; let i = index">
<app-list-element
[brand]="brand"
[id]="i"
(removeEvent)="remove($event)"
></app-list-element>
</div>
</div>
new-brand
tag component I have defined an event called newEvent
and binded to the new
method on smart-component.component.ts
.