Angular Tutorial

第三課 事件繫結 指令 版型

課程目標

  • 事件繫結範例
  • 指令 (directives)
    • 結構化指令:*ngFor, *ngIf
    • 屬性指令:ngModel
  • 初探版型套件:ng-bootstrap

事件繫結範例

  • 下拉選單的change事件
  • 按鈕的click事件

事件繫結Event Binding(1/5)

ng new EventBinding
cd EventBinding
ng g c home
<!doctype html>
<html lang="en">
 <head>
  <meta charset="utf-8">
  <title>EventBinding</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
 </head>

 <body>
  <app-root></app-root>
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
 </body>
</html>

1.新建專案   

2.修改index.html加入BootStrap CSS檔/JS檔

index.html

BS4 CSS檔

BS4 JS檔

事件繫結Event Binding(2/5)

<!--導覽列-->
<nav class="navbar navbar-dark bg-dark">
  <div class="navbar-brand"> {{ title }}</div> <!--網站標題-->
  <ul class="navbar-nav mr-auto"> <!--選單項目-->
    <li class="nav-item"><a class="nav-link" href="#">選單項目</a></li>
  </ul>
</nav>

<!--內容主體-->
<div class="container">
  <div class="m-5"></div>
  內容在此
</div>

<!--頁尾-->
<div class="jumbotron">
  <p>真理大學版權所有</p>
  <p>新北市淡水區真理街32號</p>
</div>

3.home.component.html 基本網頁格式

home.component.html

導覽列

內容主體

頁尾(用jumbotron類別)

事件繫結Event Binding(3/5)

<!--導覽列-->
<nav class="navbar navbar-dark bg-dark">
  <div class="navbar-brand"> {{ title }}</div> <!--網站標題-->
  <ul class="navbar-nav mr-auto"> <!--選單項目-->
    <li class="nav-item"><a class="nav-link" href="#">訂位</a></li>
  </ul>
</nav>
<!--內容主體-->
<div class="container">
  <div class="m-5"></div>
  <div>時段選擇:
    <select (change)="changeOption($event)">
      <option *ngFor="let day of weekdays">{{ day }}</option>
    </select>
  </div>
  <div class="m-5">
    <button class="btn btn-lg btn-outline-danger" (click)="clickme($event)"> 點選送出 </button>
  </div>
</div>
<!--頁尾-->
<div class="jumbotron">
  <p>真理大學版權所有</p>
  <p>新北市淡水區真理街32號</p>
</div>

4. app.component.html 加入下拉選單、按鈕、事件繫結

home.component.html

導覽列

下拉選單

頁尾(用jumbotron類別)

按鈕

change事件繫結

click事件繫結

事件繫結Event Binding(4/5)

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = '真善美下午茶';
  weekdays = ['星期二','星期三','星期四','星期五'];

  clickme(event){
    alert('按下按鈕');
    console.log(event);
  }

  changeOption(event){
    alert('更換選項');
    console.log(event.target.value);
  }
}

5. app.component.ts 加入事件繫結函式、屬性值

home.component.ts

屬性值

change事件繫結函式

click事件繫結值函式

事件繫結Event Binding(5/5)


  clickme(e){
    alert('按下按鈕');
    console.log(e);
  }

home.component.html

以小括弧設定

事件繫結函式

$event為系統內建之事件變數


<button class="btn btn-lg" (click)="clickme($event)"> 
點選送出 
</button>

home.component.ts

繫結之函式名稱

如不需參數:"clickme()"

繫結

練習驗收

請顯示執行畫面

找出錯誤訊息!

Angular指令Directives

使用於HTML檔內的指令

結構指令*ngFor(1/2)

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = '教士會館';
  logon = true; 
  food = [
    {name:"素猴菇三杯雞(蛋奶素)", price: 300, img:"/assets/images/mushroom.jpg"},
    {name:"養生藥膳花雕雞",price: 300, img:"/assets/images/soup.jpg"},
    {name:"北海道鮭魚定食",price: 340, img:"/assets/images/fish.jpg"},
    {name:"蘇杭東坡肉",price: 300, img:"/assets/images/meat.jpg"},
    {name:"雞肉唐揚定食",price: 300, img:"/assets/images/chicken.jpg"},
  ];
}

home.component.ts

food:物件陣列;每一元素有三個欄位 name, price, img

assets資料夾:建立images資料夾,放入適當圖片

TS檔準備好陣列food

每個元素三個欄位

陣列共5個元素

結構指令*ngFor(2/2)

<!--標題列-->
<div *ngIf="logon; else login">
  <header style="text-align: center">
    <h1>{{title}}</h1>
  </header>
  <nav>
    <!--選單列 -->
  </nav>
  <!--主體-->
  <section>
    <div class="gallery" *ngFor="let item of food">
      <img src=" {{item.img}} " />
      <div class="desc"> {{item.name}} ${{ item.price}} </div>
    </div>
  </section>

  <footer class="footer">
    Copyright © 2017 教士會館. 版權所有
  </footer>
</div>
<ng-template #login>請先登入</ng-template>

home.component.html

重複N次(N:元素個數)

*ngFor所在區塊

語法: let 迴圈變數 of 陣列名稱

迴圈變數.欄位名稱

練習

  • 加入radio選項
  • 繫結change event

練習指令(1/4)

...
<!--內容主體-->
<div class="container">
  <div class="m-5">時段選擇:
    <select (change)="changeOption($event)">
      <option *ngFor="let day of weekdays">{{ day }}</option>
    </select>
  </div>
  <div *ngIf="!optionChanged" class="text-danger">
  <p>尚未選取時段</p>
  </div>
  <div class="m-5">餐點選擇:
    <div *ngFor="let item of menu" class="form-check">
      <label class="form-check-label">
        <input class="form-check-input" type="radio" name="radio_drink" (change)="onItemChange(item)">
        {{ item.name }}
        <img src="/assets/images/{{ item.image }}" />
      </label>
    </div>
  </div>
  <div class="m-5">
    <button class="btn btn-lg btn-outline-danger" (click)="clickme($event)"> 點選送出 </button>
  </div>
</div>
...

home.component.html

*ngFor陣列

radio單選

change事件繫結

屬性的使用

*ngIf

練習指令(2/4)


<div class="form-check">
  <label class="form-check-label">
    <input class="form-check-input" type="radio" name="radio_drink" />
      單選1        
  </label>

  <label class="form-check-label">
    <input class="form-check-input" type="radio" name="radio_drink" />
      單選2
  </label>
</div>
  

form-check 包住所有選項

輸入欄位: form-check-input

name一定要相同

每一個選項顯示標籤

form-check-label

單選: radio button注意事項

<input>標籤一定要有class, type, name設定值

練習指令(3/4)

export class HomeComponent {
  title = '教士會館';
  logon = false; 
  ...

logon: 變數

成立顯示div區塊內容,否則顯示login區塊

login:

ng-template 指定的區塊名稱

ng-template內可放html內容

#區塊名稱

練習指令(4/4)

...
export class AppComponent {
  title = '真善美下午茶';
  weekdays = ['星期二','星期三','星期四','星期五'];
  menu = [
    {name:'美式咖啡', image:'coffee.png'},
    {name:'綠茶', image:'tea.png'}
  ];
  optionChanged = false;

  changeOption(event){
    alert('更換選項');
    console.log(event.target.value);
    this.optionChanged = true;
  }

  onItemChange(item){
    alert('切換選項');
    console.log(item);
  }
}

app.component.ts

新增陣列

change事件繫結函式

改變*ngIf控制變數值

控制*ngIf的變數

屬性指令ngModel

  • 將變數值綁定在html檔的輸入欄位
  • 資料編輯功能

 

 

ngModel:

But...

  • 該指令不屬於angular/core模組
  • 屬於 FormsModule 模組

 

 

修改 app.module.ts !

屬性指令ngModel

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule} from '@angular/forms'; // #1<--ngModel指令在此

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule     // #2 import FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.module.ts

加入這兩行

屬性指令ngModel

<!--標題列-->
<div *ngIf="logon; else login">
  <header style="text-align: center">
    <h1>{{title}}</h1>
  </header>
  <nav>
    <!--選單列 -->
  </nav>
  <!--主體-->
  <section>
    <div class="gallery" *ngFor="let item of food">
      <img src=" {{item.img}} " />
      <div class="desc">
        <input [(ngModel)]="item.name" placeholder="餐點名稱" >
        <div>{{ item.name }} ${{ item.price}}</div>
      </div>
    </div>
  </section>

  <footer class="footer">
    Copyright © 2017 教士會館. 版權所有
  </footer>
</div>
<ng-template #login>請先登入</ng-template>

app.component.html

修改此部份

練習:ngModel與事件

練習ngModel+event

<!--標題列-->
<div *ngIf="logon; else login">
  <header style="text-align: center">
    <h1>{{title}}</h1>
  </header>
  <nav>
    <!--選單列 -->
  </nav>
  <!--主體-->
  <section>
    <div class="gallery" *ngFor="let item of food">
      <a (click)="onSelect(item)">
      <img src=" {{item.img}} " />
      <div class="desc">
        {{ item.name }} ${{ item.price}}
      </div>
      </a>
    </div>
  </section>
  <div style="clear:both"></div>
  <h2>{{ selectedFood.name}} 已選取!</h2>

  <footer class="footer">
    Copyright © 2017 教士會館. 版權所有
  </footer>
</div>
<ng-template #login>請先登入</ng-template>

app.component.html

加上超連結

綁定click事件

顯示selectedFood

練習ngModel+event

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = '教士會館';
  logon = true;
  food = [
    {name:"素猴菇三杯雞(蛋奶素)", price: 300, img:"/assets/images/mushroom.jpg"},
    {name:"養生藥膳花雕雞",price: 300, img:"/assets/images/soup.jpg"},
    {name:"北海道鮭魚定食",price: 340, img:"/assets/images/fish.jpg"},
    {name:"蘇杭東坡肉",price: 300, img:"/assets/images/meat.jpg"},
    {name:"雞肉唐揚定食",price: 300, img:"/assets/images/chicken.jpg"},
  ];
  selectedFood=null;
  onSelect(select){
    this.selectedFood = select;
  }
}

app.component.ts

加上selectedFood變數

onSelect()事件處理器

Bootstrap版型

  • 安裝ng-bootstrap

ng-bootstrap安裝

cd 專案資料夾
npm install @ng-bootstrap/ng-bootstrap
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';

@NgModule({
  ...
  imports: [NgbModule, ...],
  ...
})
export class AppModule {
}

1. 安裝ng-bootstrap bootstrap

2. 修改app.module.ts

Accordion範例

Accordion範例


<div class="col-sm-8">
  <!--第一行 右欄 -->
  <ngb-accordion *ngFor="let article of articles">
    <ngb-panel title="{{ article.title }}">
      <ng-template ngbPanelContent>
        <h5>作者:{{ article.author }}, 日期: {{ article.date }}</h5>
        <img class="img-fluid" src="/assets/images/{{ article.image }}" />
        <p>{{ article.content }}</p>
      </ng-template>
    </ngb-panel>
  </ngb-accordion>    
</div>
  <ngb-accordion>
    <ngb-panel title="簡易標題">
      <ng-template ngbPanelContent>
       詳細內容在此
      </ng-template>
    </ngb-panel>
  </ngb-accordion>    

將原本div換成ngb-accordion

最外層:ngb-accordion

一則文章:ngb-panel

內含:ng-template

更多範例

參考

  • Accordion:文章收合
  • Alert:警告訊息
  • Carousel:輪播

練習