[Day27] 基础的 Directive

在实际工作中,我们常常会需要某一块的网页内容重复出现,像是动态的抓资料然後塞到 table 的 row 里面。笔者第一份工作刚接触前端时,连 jQuery 都不太会用,那时候凭着一股傻劲,抓完资料直接用回圈组字串塞到 table 的 innerHtml,回想起来真是好傻好天真。现在我们有了 Angular 当然不用再这样傻傻地自干,我们今天就来介绍三个基础的 Structural Directive(结构型指令)

ngFor

ngFor 指令可以从一个阵列中读出每一个元素,然後根据这些元素的内容长出 HTML 内容。上面提到的抓资料动态塞到 table row 就非常适合用 ngFor 来处理,因为一个 table 里的资料格式基本上都是固定的,只要跑回圈就能一个萝卜一个坑,一行一行的把 row 加到 table 里就能把所有资料显示出来。

上次我们用 IronmanComponent 来显示单一使用者的资讯,今天我们来新增一个 component,用 table 显示一个使用者清单。

在我们加入越来越多自己的东西之後,Angular 自动产生的 HTML 内容会显得很碍眼,现在可以视个人喜好决定要不要把 删掉。笔者是留下上面的 ToolBar,然後<div class="content" role="main"> 里除了 <router-outlet></router-outlet> 全砍了

首先一样用指令或者 Extension 的功能新增一个 component,这里笔者就叫他 ironman-list。

  1. 在 ironman-list.component.ts 里宣告一个 @Input() 变数,以阵列的形式储存使用者资讯
  @Input()
  userList: IronmanUser[] = [];
  1. 在 app.component.ts 建立一个使用者列表的假资料
userListFromAppComponent: IronmanUser[] = [
    {
      userId: 1,
      userName: 'Alice',
      email: '[email protected]',
      verified: 1
    },
	// ...
    // 其他资料
    // ...
]
  1. 在 app.component.html 使用 selector 选取并嵌入 ironman-list,同时用属性系结把使用者列表传给 ironman-list。这时候可以把之前的<app-ironman></app-ironman>删掉或注解
  <!-- <app-ironman 
    [(userInfo)]=userInfoFromAppComponent 
    (testOuputEvent)=handleTestEvent($event)>
  </app-ironman> -->
  <app-ironman-list [userList]=userListFromAppComponent></app-ironman-list>

  1. 最後,在 ironman-list.html 中,使用 *ngFor 把传进来的使用者列表加到 table 里
 <tbody>
    <tr *ngFor="let user of userList">
      <td>{{user.userId}}</td>
      <td>{{user.userName}}</td>
      <td>{{user.email}}</td>
      <td>{{user.verified}}</td>
    </tr>
  </tbody>

执行程序,应该就能看到我们只写了一份 <tr>…</tr> 就长出所有的内容了!这里我们来稍微解释一下 ngFor 的语法:

  • *ngFor 需要一个宿主元素,他会执行回圈重复渲染(render)这个宿主与他所包含的元素
  • let user of userList 代表这个 for 回圈的资料来源是同个 component 中的 userList 变数,每个回圈会把 userList 的元素取出来放在 user 变数
  • 任何被宿主包住的元素都能存取 ngFor 宣告的变数(let user),我们这里使用内嵌系结把资料嵌入到 td 元素中
    https://ithelp.ithome.com.tw/upload/images/20210927/20140664YE2e3l7OcM.png

ngIf

网页应用中,我们也常常会需要根据资料的某个栏位,来决定要不要显示某个内容,而这种需求,我们可以很容易地利用 *ngIf 来达到。这里我们就来就绍一下 *ngIf 的用法。

假设我们今天的需求是:如果某个使用者已经通过认证,那管理员就能点编辑按钮编辑这个使用者的资料,那我们只要对刚刚的 table 稍作修改,加入一行 *ngIf 的语法,就能达到这样的效果

<tbody>
    <tr *ngFor="let user of userList">
        <td>{{user.userId}}</td>
        <td>{{user.userName}}</td>
        <td>{{user.email}}</td>
        <td>{{user.verified}}</td>
        <td>
            <button *ngIf="user.verified === 1">编辑</button>
        </td>
    </tr>
</tbody>

上面的程序中,*ngIf 的宿主是 button 元素,而且这个 button 只有在 user.verified 这个属性等於 1 的时候才会被渲染出来。
https://ithelp.ithome.com.tw/upload/images/20210927/20140664EXoy76HxOp.png

ngSwitch

有些时候,我们可能不只需要用二分法来决定页面的显示,可能需要根据不同的值来显示不同的内容,ngIf 虽然能做到,但是程序码看起来总会觉得有点脏,这时候,ngSwitch 就派上用场了!

首先,先在 app.component.ts 的资料来源中加一笔 verified 有异常值的假资料,不然我们目前只有 0 跟 1 XD

userListFromAppComponent: IronmanUser[] = [
   // 前面不变
    {
      userId: 999,
      userName: 'Bug',
      email: '',
      verified: -1
    },

接着,稍微修改一下 ironman-list.component.html 的内容,把原本单纯输出 verified 的地方改成 ngSwitch

<tbody>
    <tr *ngFor="let user of userList">
      <td>{{user.userId}}</td>
      <td>{{user.userName}}</td>
      <td>{{user.email}}</td>
      <td [ngSwitch]="user.verified">
        <p *ngSwitchCase="1">已认证</p>
        <a *ngSwitchCase="0" href="#">前往认证</a>
        <p *ngSwitchDefault class="text-danger;">BUG</p>
      </td>
      <td>
        <button *ngIf="user.verified === 1">编辑</button>
      </td>
    </tr>

ngSwitch 一样需要一个宿主,然後在这个宿主里面,只有条件成立的 case 会被渲染出来。执行程序就会看到我们的 table 根据不同的 verified 属性值显示不同的元素,这里稍微注意一下 ngSwitch 的语法有点不同,switch 的地方是用中括号的属性系结,case 的地方才是用 directive(星号)。
https://ithelp.ithome.com.tw/upload/images/20210927/20140664vDpFsOSi3m.png

用 ng-container 当宿主

有些时候,如果我们所使用的 CSS 在选取上很难改,擅自增加一个宿主元素可能会让 CSS 跑掉,这个时候我们可以多写一个 <ng-container></ng-container> 来当宿主,ng-container 在被编译成 JS 之後会变成注解,所以就不会影响到 CSS 的目标选取。例如,上面的 ngIf 也可以改成

<td>
    <ng-container [ngSwitch]="user.verified">
      <p *ngSwitchCase="1">已认证</p>
      <a *ngSwitchCase="0" href="#">前往认证</a>
      <p *ngSwitchDefault class="text-danger">BUG</p>
    </ng-container>
</td>

https://ithelp.ithome.com.tw/upload/images/20210927/201406642pZi6aYlj1.png

以上就是最基本、常用的三个结构型指令(structural directive),用这三个结构型指令就能让我们很灵活的决定网页的内容。明天,我们会介绍一下基本的 Angular 的 HttpClient,这样我们就真的不用把资料写死了。


<<:  快乐打包又很坑的pyinstaller

>>:  110/12 - 把照片储存在Pictures/应用程序名称资料夹 - 2

Day1 初探NodeJS

学习新知的第一步是初步了解原理,学习新的开发技术除了原理也要先学习设定环境。 写在最最最前面 虽然N...

Angular 深入浅出三十天:表单与测试 Day25 - 测试进阶技巧 - DI 抽换

好一阵子没写单元测试与整合测试了,大家是否觉得有些生疏了呢? 之前的测试都写得很简单,正好昨天好好...

[Day22]DML语句实作

解释以下SQL语句: INSERT INTO departments(department_id, ...

DAY6 建立Messaging API channel

各位可以把频道(Channel)想像是服务提供者(Provider)所建立的LINE帐号,藉此和使用...

Day12# interface

第 12 天要来介绍 interface 那麽话不多说,我们就进入正题吧 ─=≡Σ(((っ゚∀゚)っ...