Angular Tutorial 3章

Interpolation(補完) (P1162)

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

@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}. Hello {{user?.name}}</h1>`,
})
export class AppComponent  {
  name = 'Angular';
  // user: User = {
  //   id: "1",
  //   name: "yohei"
  // }
}

class User {
  id: string;
  name: string;
}

プロパティバインディング (P1232)

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

@Component({
  selector: 'my-app',
  template: `<img [src]="image" />`
})
export class AppComponent  {
  image = 'http://www.wings.msn.to/image/wings.jpg'
}

インナーHTML (P1265)

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  template: `<div [innerHTML]="msg"></div>`
})
export class AppComponent  {
  msg = `<h2>hello</h2><br><input type="button" onclick="alert('OK')" value="クリック" />`
}

inputタグは出力されない

出力結果

<div>
  <h2>hello</h2>
</div>

以下のようにsafe処理を行う必要がある

src/app/app.component.ts

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

// モジュール読み込み
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

@Component({
  selector: 'my-app',
  // safeMsgの読み込み
  template: `<div [innerHTML]="safeMsg"></div>`
})
export class AppComponent  {
  constructor(private sanitizer: DomSanitizer){
    // safeMsg生成
    this.safeMsg = sanitizer.bypassSecurityTrustHtml(this.msg)
  }
  msg = `<h2>hello</h2><br><input type="button" onclick="alert('OK')" value="クリック" />`;
  safeMsg: SafeHtml;
}

属性バインディング(P1358)

プロパティバインディングが使えない場合は、属性バインディングを使う。極力、プロパティバインディングを使うべき。
以下の例ではプロパティバインディングは使えない。
例えば、imgのimg属性は、imgプロパティを持ち、inputのvalueはvalueプロパティを持っているので
プロパティバインディングを使えるが、tdのrowspan属性は、rowspanプロパティを持っていないため。

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  template: `
    <table border="1">
      <tr>
        // 属性バインディング
        <td [attr.rowspan]="len">結合</td>
        <td>1</td>
      </tr>
      <tr><td>2</td></tr>
      <tr><td>3</td></tr>
    </table>
  `
})
export class AppComponent  {
  len = 3;
}

クラスバインディング(P1414)

元々のline classは打ち消されてしまう。

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

@Component({
  selector: 'my-app',
  template: `<div class="line" [class]="myclass">hello</div>`,
  styles: [`
    .red { color: Red; }
    .line { border: solid 1px #f00;}
  `]
})
export class AppComponent  {
  myclass = "red"
}

クラスバインディング(P1433)

クラスは複数設定することが可能

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

@Component({
  selector: 'my-app',
  template: `<div class="line" [class.red]="red">hello</div>`,
  styles: [`
    .red { color: Red; }
    .line { border: solid 1px #f00;}
  `]
})
export class AppComponent  {
  // trueにするとredクラスが追加される。falseにすると削除される
  red = true;
}

スタイルバインディング(P1462)

<div [style.backgroud-color]="bcolor">test<div>

イベントバインディング(P1598)

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  // $eventとしないと、eventをハンドラの中で呼び出せない
  template: `<input type="button" (click)="show($event)" value="現在時刻"/>{{msg}}`,
})
export class AppComponent  {
  msg = "";

  show(e: any){
    this.msg = new Date().toLocaleString();
    console.log(e);
  }
}

イベントのデフォルトをキャンセル(P1657)

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

@Component({
  selector: 'my-app',
  template: `
    <div class="line" [class.red]="red">hello</div>
    <input type="text" (keypress)="mask($event)" value="現在時刻"/>{{msg}}
  `,
})
export class AppComponent  {
  msg = "hello";

  mask(e: any){
    let k = e.which;
    // aを入力した時のみ入力を禁止
    if (k == 97){
      e.preventDefault();
    }
  }
}

バブルのイベントをキャンセル

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  {
  onclick1(e: any){
    console.log('outer')
  }
  onclick2(e: any){
    console.log('inner')
    // 以下でキャンセルを行わないと、innerをクリックした際にouterも反応してしまう。上位階層にイベントがバブリングしていくのを防ぐ

    e.stopPropagation();
  }
}

src/app/app.component.html

<div id="outer" (click)="onclick1()">outer
  <div id="inner" (click)="onclick2($event)">
    inner
  </div>
</div>

src/app/app.component.css

#outer{
  height: 200px;
  width: 350px;
  margin: 50px;
  background-color: red;
}

#inner{
  height: 50px;
  width: 100px;
  margin: 50px;
  background-color: blue;
}

変数の入力値の取得(P1676)

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  {
  msg = ''
  show(txt: string){
    this.msg = txt
  }
}

src/app/app.component.html

<input #txt type="text" (input)="show(txt.value)">
<div>{{msg}}</div>

テンプレート参照変数による入力値の取得(P1710)

src/app/app.component.html

//(change)="0" を入れることで、componentファイル不要で変数をバインディングできる。コンポーネントでの定義は不要。
<input #last type="text" (change)="0">
<input #first type="text" (change)="0">
{{last.value}}{{first.value}}

キーイベントのフィルタリング(P1719)

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  {
  msg = ''
  show(s: string){
    this.msg = s;
  }
}

enterkeyを押した時のみハンドラが実行される

src/app/app.component.html

<input #txt type="text" (keyup.enter)="show(txt.value)">
{{msg}}

双方向バインディング(P1763)

プロパティバインディングとイベントバインディングをそれぞれ使う実装

FormsModuleを追加

src/app/app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule} from '@angular/forms'
import { AppComponent }  from './app.component';

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

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  {
  myName = '宮本'
  show(s: string){
    this.myName = s;
  }
}

プロパティバインディングとイベントバインディングをそれぞれ実装

src/app/app.component.html

// [ngModel]="myName" はプロパティバインディング
// (input)="show(txt.value)" はイベントバインディグ
<form>
  <input #txt id="name" type="text" name="name" [ngModel]="myName" (input)="show(txt.value)">
  <div>こんにちは{{myName}}さん</div>
</form>

双方向バインディングを使った実装

以下のようにシンプルに実装できる。イベントバインディングハンドラ show(s: string) を実装する必要もなくなる。データバインディング(プロパティバインディングとイベントバインディング)が双方向に行われる。

<form>
  // 角括弧と括弧で囲む
  <input id="name" type="text" name="name" [(ngModel)]="myName">
  <div>こんにちは{{myName}}さん</div>
</form>

データーバインディング時の入力値の加工(P1826)

ハンドラの定義を行わない実装

<form>
  <input id="name" type="text" name="name" [ngModel]="myName" (ngModelChange)="myName=$event.toUpperCase()"> // 入力値を大文字に変換
  <div>こんにちは{{myName}}さん</div>
</form>

ハンドラ定義を行う実装

src/app/app.component.ts

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent  {
  myName = '宮本'
  // イベントハンドラを実装
  upper(s: string){
    return s.toUpperCase();
  }
}

src/app/app.component.html

<form>
  <input id="name" type="text" name="name" [ngModel]="myName" (ngModelChange)="myName=upper($event)"> // イベントハンドラを実装
  <div>こんにちは{{myName}}さん</div>
</form>