Angular Directives — NgSwitch, Input, and Output

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at the NgSwitch directive, template variables, and Input and Ouput syntax.

The NgSwitch directives

We can use the NgSwitch directive to display an item from a list of possible choices.

For example, we can use it as follows:

app.component.ts:

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

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  name = "foo";  
}
Enter fullscreen mode Exit fullscreen mode

app.component.html:

<div [ngSwitch]="name">  
  <p *ngSwitchCase="'foo'">foo</p>  
  <p *ngSwitchCase="'bar'">bar</p>  
  <p *ngSwitchCase="'baz'">baz</p>  
</div>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the name field in AppComponent set to 'foo'.

Then in app.component.html, we have ngSwitch set to name so that it checks the value of name in AppComponent to get what to display.

We have multiple *ngSwitchCase with different values so that if name is 'foo', we display ‘foo’, if name is 'bar' then we display ‘bar’, and if name is 'baz', we display ‘baz’.

Since name is ‘foo’, we display ‘foo’.

*ngSwitchCase works with both native elements and components.

Template Reference Variables (#var)

A template reference variable is often a reference to a DOM element within a template. It can also refer to a directive, an element. TemplateRef or a web component.

For example, we can use it as follows:

app.component.ts:

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

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  call(phone) {  
    alert(`Calling ${phone.value}`);  
  }  
}
Enter fullscreen mode Exit fullscreen mode

app.component.html :

<input #phone placeholder="phone" />  
<button (click)="call(phone)">Call</button>
Enter fullscreen mode Exit fullscreen mode

In the code above, we added a call method which takes in the phone element as the argument and shows an alert with the value typed into the phone input.

Then we added #phone in app.component.html to reference the input element. Also, we added a button to call the call method with the phone input reference so that we can show the value in the alert.

NgForm

The NgForm directive change behavior and set the value of the template variable to something else.

With it, we can reference the form with a variable inside our outside the form.

For example, we can use NgForm as follows:

app.component.ts:

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

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {  
  onSubmit(itemForm) {  
    if (itemForm.invalid) {  
      return;  
    }  
    alert("form submitted");  
  }  
}
Enter fullscreen mode Exit fullscreen mode

app.component.html:

<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">  
  <label>Name <input name="name" ngModel required /> </label>  
  <button type="submit">Submit</button>  
</form>
<div [hidden]="itemForm.form.valid">  
  <p>Missing name</p>  
</div>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the onSubmit method in AppComponent, which takes the itemForm reference. Then we can use it to check for validity in the component before submitting.

Then in app.component.html, we created the #itemForm variable by using the ngForm directive so that we can reference the form and check its validity in the bottom div and in onSubmit with itemForm passed in.

Alternative Syntax

We can use the ref- prefix instead of #, so we can write:

<input ref-phone placeholder="phone" />  
<button (click)="call(phone)">Call</button>
Enter fullscreen mode Exit fullscreen mode

@Input() and @Output() Properties

@Input and @Output allow Angular to share data between the parent context and child directives and components.

How to use @Input()

For example, we can write the following to use @Input to pass in data from the parent component to the child:

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';  
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';  
import { AppComponent } from './app.component';  
import { PersonComponent } from './person/person.component';
@NgModule({  
  declarations: [  
    AppComponent,  
    PersonComponent  
  ],  
  imports: [  
    BrowserModule,  
    AppRoutingModule  
  ],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

app.component.ts:

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

@Component({  
  selector: 'app-root',  
  templateUrl: './app.component.html',  
  styleUrls: ['./app.component.css']  
})  
export class AppComponent {  
  persons = [{ name: 'Jane' }, { name: 'John' }, { name: 'Mary' }];  
}
Enter fullscreen mode Exit fullscreen mode

app.component.html:

<app-person *ngFor="let p of persons" [person]='p'></app-person>
Enter fullscreen mode Exit fullscreen mode

person.component.ts:

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

@Component({  
  selector: 'app-person',  
  templateUrl: './person.component.html',  
  styleUrls: ['./person.component.css']  
})  
export class PersonComponent {  
  @Input() person;  
}
Enter fullscreen mode Exit fullscreen mode

person.component.html:

<div>{{person.name}}</div>
Enter fullscreen mode Exit fullscreen mode

In the code above, we created a PersonComponent component and then included it in the declarations array of AppModule.

Then in AppComponent, we have:

persons = [{ name: 'Jane' }, { name: 'John' }, { name: 'Mary' }];
Enter fullscreen mode Exit fullscreen mode

and *ngFor in app.component.html to loop through the items and render the PersonComponent.

We pass in p as the value of the person property and then it’ll be the value of person in the PersonComponent.

Finally, we display the name value of person in person.component.html.

In the end, we should see:

JaneJohnMary
Enter fullscreen mode Exit fullscreen mode

displayed on the screen.

How to use @Output()

We can use the @Output decorator in the child component or directive to pass data from child to parent.

For example, we can use it as follows:

app.module.ts:

import { BrowserModule } from '@angular/platform-browser';  
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';  
import { AppComponent } from './app.component';  
import { PersonComponent } from './person/person.component';

@NgModule({  
  declarations: [  
    AppComponent,  
    PersonComponent  
  ],  
  imports: [  
    BrowserModule,  
    AppRoutingModule  
  ],  
  providers: [],  
  bootstrap: [AppComponent]  
})  
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

app.component.ts:

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

@Component({  
  selector: 'app-root',  
  templateUrl: './app.component.html',  
  styleUrls: ['./app.component.css']  
})  
export class AppComponent {  
  emittedName: string;  
}
Enter fullscreen mode Exit fullscreen mode

app.component.html:

<app-person (name)='emittedName = $event'></app-person>  
<p>{{emittedName}}</p>
Enter fullscreen mode Exit fullscreen mode

person.component.ts:

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

@Component({  
  selector: 'app-person',  
  templateUrl: './person.component.html',  
  styleUrls: ['./person.component.css']  
})  
export class PersonComponent {  
  @Output() name = new EventEmitter<string>();  
  emitName() {  
    this.name.emit('Jane');  
  }  
}
Enter fullscreen mode Exit fullscreen mode

person.component.html:

<button (click)='emitName()'>Get Name</button>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the button in person.component.html which calls the PersonComponent’s emitName method to emit the string 'Jane' to the parent component with the EventEmitter.

Then in the parent component, AppComponent, we have:

<app-person (name)='emittedName = $event'></app-person>
Enter fullscreen mode Exit fullscreen mode

in app.component.html.

$event has the value emitted from the name emitter. Then we set it to emittedName and displayed it.

@Input() and @Output() together

We can use them together.

For example, we can write:

<app-input-output [item]="currentItem" (deleteRequest)="deleteItem($event)"></app-input-output>
Enter fullscreen mode Exit fullscreen mode

In the code above, we pass currentItem to the item property to the app-input-output component.

The deleteRequest is emitted from app-input-output and then the deleteItem method is called with what’s passed from the child when deleteRequest is emitted.

We can pass in a name to Input and Output to change the name of them respective and then we can reference them with that name in our templates.

Conclusion

We can use NgSwitch to display an item depending on value of something in the component.

Template variables let us reference DOM elements in our templates and access its properties.

With Input and Output, we can pass data to a child component or directive and pass items from child to parent respectively.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .