-
08 구조 디렉티브(Structural Directive) 06앵귤러/03 템플릿&데이터 바인딩 2017. 9. 2. 13:06
요약
라이브 예제 / 예제 다운로드에서 이 가이드의 소스 코드를 다운로드 할 수 있습니다.
다음은 src/app/ 폴더의 소스입니다.
src/app/app.component.ts
import { Component } from '@angular/core';
import { Hero, heroes } from './hero';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
heroes = heroes;
hero = this.heroes[0];
condition = false;
logs: string[] = [];
showSad = true;
status = 'ready';
trackById(index: number, hero: Hero): number { return hero.id; }
}
src/app/app.component.html
<h1>Structural Directives</h1>
<p>Conditional display of hero</p>
<blockquote>
<div *ngIf="hero" >{{hero.name}}</div>
</blockquote>
<p>List of heroes</p>
<ul>
<li *ngFor="let hero of heroes">{{hero.name}}</li>
</ul>
<hr>
<h2 id="ngIf">NgIf</h2>
<p *ngIf="true">
Expression is true and ngIf is true.
This paragraph is in the DOM.
</p>
<p *ngIf="false">
Expression is false and ngIf is false.
This paragraph is not in the DOM.
</p>
<p [style.display]="'block'">
Expression sets display to "block".
This paragraph is visible.
</p>
<p [style.display]="'none'">
Expression sets display to "none".
This paragraph is hidden but still in the DOM.
</p>
<h4>NgIf with template</h4>
<p><ng-template> element</p>
<ng-template [ngIf]="hero">
<div>{{hero.name}}</div>
</ng-template>
<p>template attribute</p>
<div template="ngIf hero">{{hero.name}}</div>
<hr>
<h2 id="ng-container"><ng-container></h2>
<h4>*ngIf with a <ng-container></h4>
<button (click)="hero = hero ? null : heroes[0]">Toggle hero</button>
<p>
I turned the corner
<ng-container *ngIf="hero">
and saw {{hero.name}}. I waved
</ng-container>
and continued on my way.
</p>
<p>
I turned the corner
<span *ngIf="hero">
and saw {{hero.name}}. I waved
</span>
and continued on my way.
</p>
<p><i><select> with <span></i></p>
<div>
Pick your favorite hero
(<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
<span *ngFor="let h of heroes">
<span *ngIf="showSad || h.emotion !== 'sad'">
<option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
</span>
</span>
</select>
<p><i><select> with <ng-container></i></p>
<div>
Pick your favorite hero
(<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
<ng-container *ngFor="let h of heroes">
<ng-container *ngIf="showSad || h.emotion !== 'sad'">
<option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
</ng-container>
</ng-container>
</select>
<br><br>
<hr>
<h2 id="ngFor">NgFor</h2>
<div class="box">
<p class="code"><div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd"></p>
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
<p class="code"><div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd"></p>
<div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
<p class="code"><template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById"></p>
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
<div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
</div>
<hr>
<h2 id="ngSwitch">NgSwitch</h2>
<div>Pick your favorite hero</div>
<p>
<label *ngFor="let h of heroes">
<input type="radio" name="heroes" [(ngModel)]="hero" [value]="h">{{h.name}}
</label>
<label><input type="radio" name="heroes" (click)="hero = null">None of the above</label>
</p>
<h4>NgSwitch</h4>
<div [ngSwitch]="hero?.emotion">
<happy-hero *ngSwitchCase="'happy'" [hero]="hero"></happy-hero>
<sad-hero *ngSwitchCase="'sad'" [hero]="hero"></sad-hero>
<confused-hero *ngSwitchCase="'confused'" [hero]="hero"></confused-hero>
<unknown-hero *ngSwitchDefault [hero]="hero"></unknown-hero>
</div>
<h4>NgSwitch with <i>template</i> attribute</h4>
<div [ngSwitch]="hero?.emotion">
<happy-hero template="ngSwitchCase 'happy'" [hero]="hero"></happy-hero>
<sad-hero template="ngSwitchCase 'sad'" [hero]="hero"></sad-hero>
<confused-hero template="ngSwitchCase 'confused'" [hero]="hero"></confused-hero>
<unknown-hero template="ngSwitchDefault" [hero]="hero"></unknown-hero>
</div>
<h4>NgSwitch with <ng-template></h4>
<div [ngSwitch]="hero?.emotion">
<ng-template [ngSwitchCase]="'happy'">
<happy-hero [hero]="hero"></happy-hero>
</ng-template>
<ng-template [ngSwitchCase]="'sad'">
<sad-hero [hero]="hero"></sad-hero>
</ng-template>
<ng-template [ngSwitchCase]="'confused'">
<confused-hero [hero]="hero"></confused-hero>
</ng-template >
<ng-template ngSwitchDefault>
<unknown-hero [hero]="hero"></unknown-hero>
</ng-template>
</div>
<hr>
<h2><template></h2>
<p>Hip!</p>
<ng-template>
<p>Hip!</p>
</ng-template>
<p>Hooray!</p>
<hr>
<h2 id="myUnless">UnlessDirective</h2>
<p>
The condition is currently
<span [ngClass]="{ 'a': !condition, 'b': condition, 'unless': true }">{{condition}}</span>.
<button
(click)="condition = !condition"
[ngClass] = "{ 'a': condition, 'b': !condition }" >
Toggle condition to {{condition ? 'false' : 'true'}}
</button>
</p>
<p *myUnless="condition" class="unless a">
(A) This paragraph is displayed because the condition is false.
</p>
<p *myUnless="!condition" class="unless b">
(B) Although the condition is true,
this paragraph is displayed because myUnless is set to false.
</p>
<h4>UnlessDirective with template</h4>
<p *myUnless="condition">Show this sentence unless the condition is true.</p>
<p template="myUnless condition" class="code unless">
(A) <p template="myUnless condition" class="code unless">
</p>
<ng-template [myUnless]="condition">
<p class="code unless">
(A) <template [myUnless]="condition">
</p>
</ng-template>
src/app/app.component.css
button {
min-width: 100px;
font-size: 100%;
}
.box {
border: 1px solid gray;
max-width: 600px;
padding: 4px;
}
.choices {
font-style: italic;
}
code, .code {
background-color: #eee;
color: black;
font-family: Courier, sans-serif;
font-size: 85%;
}
div.code {
width: 400px;
}
.heroic {
font-size: 150%;
font-weight: bold;
}
hr {
margin: 40px 0
}
.odd {
background-color: palegoldenrod;
}
td, th {
text-align: left;
vertical-align: top;
}
p span { color: red; font-size: 70%; }
.unless {
border: 2px solid;
padding: 6px;
}
p.unless {
width: 500px;
}
button.a, span.a, .unless.a {
color: red;
border-color: gold;
background-color: yellow;
font-size: 100%;
}
button.b, span.b, .unless.b {
color: black;
border-color: green;
background-color: lightgreen;
font-size: 100%;
}
src/app/app.module.ts
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { heroSwitchComponents } from './hero-switch.components';
import { UnlessDirective } from './unless.directive';
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [
AppComponent,
heroSwitchComponents,
UnlessDirective
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
src/app/hero.ts
export class Hero {
id: number;
name: string;
emotion?: string;
}
export const heroes: Hero[] = [
{ id: 1, name: 'Mr. Nice', emotion: 'happy'},
{ id: 2, name: 'Narco', emotion: 'sad' },
{ id: 3, name: 'Windstorm', emotion: 'confused' },
{ id: 4, name: 'Magneta'}
];
src/app/hero-switch.components.ts
import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'happy-hero',
template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.`
})
export class HappyHeroComponent {
@Input() hero: Hero;
}
@Component({
selector: 'sad-hero',
template: `You like {{hero.name}}? Such a sad hero. Are you sad too?`
})
export class SadHeroComponent {
@Input() hero: Hero;
}
@Component({
selector: 'confused-hero',
template: `Are you as confused as {{hero.name}}?`
})
export class ConfusedHeroComponent {
@Input() hero: Hero;
}
@Component({
selector: 'unknown-hero',
template: `{{message}}`
})
export class UnknownHeroComponent {
@Input() hero: Hero;
get message() {
return this.hero && this.hero.name ?
`${this.hero.name} is strange and mysterious.` :
'Are you feeling indecisive?';
}
}
export const heroSwitchComponents =
[ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ];
src/app/unless.directive.ts
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
/**
* Add the template content to the DOM unless the condition is true.
*
* If the expression assigned to `myUnless` evaluates to a truthy value
* then the templated elements are removed removed from the DOM,
* the templated elements are (re)inserted into the DOM.
*
* <div *ngUnless="errorCount" class="success">
* Congrats! Everything is great!
* </div>
*
* ### Syntax
*
* - `<div *myUnless="condition">...</div>`
* - `<div template="myUnless condition">...</div>`
* - `<template [myUnless]="condition"><div>...</div></template>`
*
*/
@Directive({ selector: '[myUnless]'})
export class UnlessDirective {
private hasView = false;
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
@Input() set myUnless(condition: boolean) {
if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}
}
당신은 다음 내용을 학습하였습니다.
l 구조 디렉티브는 HTML 레이아웃을 조작합니다.
l 적합한 호스트 엘리먼트가 없을 때 <ng-container>를 그룹화 엘리먼트로 사용합니다.
l Angular 별표(*) 구문을 <ng-template>로 해석합니다.
l NgIf, NgFor 및 NgSwitch 내장 디렉티브에 대한 작동 방식
l <ng-template>으로 확장되는 microsyntax에 대해서.
l 사용자 지정 구조 디렉티브 인 UnlessDirective를 작성하였습니다.
'앵귤러 > 03 템플릿&데이터 바인딩' 카테고리의 다른 글
09 파이프(Pipe) 02 (0) 2017.09.02 09 파이프(Pipe) 01 (0) 2017.09.02 08 구조 디렉티브(Structural Directive) 05 (0) 2017.09.02 08 구조 디렉티브(Structural Directive) 04 (0) 2017.09.02 08 구조 디렉티브(Structural Directive) 03 (0) 2017.09.02