在实际的前后台对接过程中,后台更倾向于把原始的数据发送给前台。比如教师性别字段,往往返回给前台是`0`和`1`,而不是`男`和`女`。前台接收到原始值以后按实际的需求展示。
## 使用boolean值表示男女
我们打开C层文件`app.component.ts`,将其中的性别由字符串类型修改为boolean类型。
```typescript
// 定义教师数组
teachers = [{
id: 1,
name: '张三',
username: 'zhangsan',
email: 'zhangsan@yunzhiclub.com',
sex: true ❶
}, {
id: 2,
name: '李四',
username: 'lisi',
email: 'lisi@yunzhiclub.com',
sex: false, ❶
}];
```
* ❶ true表示男,false表示女。
![](https://img.kancloud.cn/0d/c3/0dc32f524935dc96fa5ae48be85958e7_439x97.png)
## *ngIf
上节中我们学习了Angular的内置指令`*ngFor`,本节我们使用`*ngIf`来显示性别。`*ngIf`的使用方法非常的简单。
```html
<table>
<tr>
<th>序号</th>
<th>姓名</th>
<th>用户名</th>
<th>邮箱</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr *ngFor="let teacher of teachers; index as i">
<td>{{ i + 1 }}</td>
<td>{{ teacher.name }}</td>
<td>{{ teacher.username }}</td>
<td>{{ teacher.email }}</td>
<td *ngIf="teacher.sex❶">男</td>
<td *ngIf="!teacher.sex❷">女</td>
<td>删除</td>
</tr>
</table>
```
![](https://img.kancloud.cn/97/4d/974dc221b40e7f30b7eca860a8322e8e_433x95.png)
* ❶ `teacher.sex`为真时显示宿主标签
* ❷ `teacher.sex`为假时显示宿主标签
## 结构化
上述的实现方案并不理想,原因是其破坏了代码的`结构`,这很容易团队中的其它小伙伴(包括一段时间后的自己)带来误伤。
其原因是上述代码`table`中的第一个`tr`中我们输出了5个`th`,但却在第二个`tr`中输出了6个`td`。而标准的HTML来中如果表格中的行列没有经过合并,则第行中的列数必然是相等的,如果不相等则可以认为发生了错误。虽然我们是在使用Angular框架,其能够动态的规划HTML,但仍然不应该在模块中给别人造成误读,或者说仍然不应该给团队中的其它成员增加阅读代码的成本。
如果将代码改成如下这样,则规避了上述误会。
```html
<tr *ngFor="let teacher of teachers; index as i">
<td>{{ i + 1 }}</td>
<td>{{ teacher.name }}</td>
<td>{{ teacher.username }}</td>
<td>{{ teacher.email }}</td>
<td>
<span *ngIf="teacher.sex">男</span>
<span *ngIf="!teacher.sex">女</span>
</td>
<td>删除</td>
</tr>
```
![](https://img.kancloud.cn/97/4d/974dc221b40e7f30b7eca860a8322e8e_433x95.png)
查看生成源码:
```html
<td _ngcontent-a-c16="">
<span _ngcontent-a-c16="">男</span> ❶
<!--bindings={
"ng-reflect-ng-if": "true"
}-->
<!--bindings={
"ng-reflect-ng-if": "false"
}-->
</td>
<td _ngcontent-a-c16="">
<!--bindings={
"ng-reflect-ng-if": "false"
}-->
<span _ngcontent-a-c16="">女</span> ❷
<!--bindings={
"ng-reflect-ng-if": "true"
}-->
</td>
```
* ❶ 第一个`*ngIf`生效时
* ❷ 第二个`*ngIf`生效时
* 😀 以注释出现的内容为angular自动生成,目的是帮助我们了解模板解析的过程
仔细观察我们能够轻易发现,在上述代码中我们增加了冗余的标签`<span>`。在大多数时候,这样做无可厚非。在有些时候,比如我们在`css`中对样式进行了精确的控制,则可能由于我们增加的这个`<span>`标签而导致样式失效。这时便可以使用`else`结合**永远不会显示出来**的`<ng-template>`
## else 与 ng-template
有`if`的地方,则必然可以使用`else`,Angular也不例外。
```html
<tr *ngFor="let teacher of teachers; index as i">
<td>{{ i + 1 }}</td>
<td>{{ teacher.name }}</td>
<td>{{ teacher.username }}</td>
<td>{{ teacher.email }}</td>
<td *ngIf="teacher.sex; else❶ femaleBlock❷">男</td>❹
<td>删除</td>
</tr>
</table>
<ng-template❺ #femaleBlock❸>
<td>女</td>❻
</ng-template>
```
* ❶ else关键字出现在`*ngIf`中
* ❷ 该名字自己随意起,作用是进行关键字的标识。当else条件成立时,Angular将按此标识去查找对应的元素(模板)。
* ❸ 与❷相对应,表示else成立时使用本元素来替换`*ngIf`的宿主元素❹
* ❺ `<ng-template>`具有**永远不会显示出来**的特性,所以当else成立时,在生成的HTML代码中也找不到`<ng-template>`的身影
* ❻ 做为`<ng-template>`中的内容,当else成立时,被用来替换`*ngIf`的宿主元素❹
![](https://img.kancloud.cn/97/4d/974dc221b40e7f30b7eca860a8322e8e_433x95.png)
查看生成源码:
```html
<td _ngcontent-a-c16="">男</td>
...
<td _ngcontent-a-c16="">女</td>
```
在源码出我们并没有找到任何关于`<ng-template>`的信息,也印证了其**永远不会显示出来**的特性。
好了,休息,休息一会。
# 本节作业
请阅读官方文档中的[NgSwitch指令](https://www.angular.cn/guide/built-in-directives#the-ngswitch-directives),**尝试**使用 `ngSwitch` 来显示性别。
# 资源列表
| 名称 | 地址 |
|---- | ---- |
| API -> NgIf | [https://www.angular.cn/api/common/NgIf](https://www.angular.cn/api/common/NgIf) |
| 内置指令 -> NgIf | [https://www.angular.cn/guide/built-in-directives#ngif](https://www.angular.cn/guide/built-in-directives#ngif) |
| <ng-template>元素 | [https://www.angular.cn/guide/structural-directives#the-ng-template](https://www.angular.cn/guide/structural-directives#the-ng-template)
| 本节源码 | [https://github.com/mengyunzhi/angular11-guild/archive/step2.1.4.zip](https://github.com/mengyunzhi/angular11-guild/archive/step2.1.4.zip)
- 序言
- 第一章 Hello World
- 1.1 环境安装
- 1.2 Hello Angular
- 1.3 Hello World!
- 第二章 教师管理
- 2.1 教师列表
- 2.1.1 初始化原型
- 2.1.2 组件生命周期之初始化
- 2.1.3 ngFor
- 2.1.4 ngIf、ngTemplate
- 2.1.5 引用 Bootstrap
- 2.2 请求后台数据
- 2.2.1 HttpClient
- 2.2.2 请求数据
- 2.2.3 模块与依赖注入
- 2.2.4 异步与回调函数
- 2.2.5 集成测试
- 2.2.6 本章小节
- 2.3 新增教师
- 2.3.1 组件初始化
- 2.3.2 [(ngModel)]
- 2.3.3 对接后台
- 2.3.4 路由
- 2.4 编辑教师
- 2.4.1 组件初始化
- 2.4.2 获取路由参数
- 2.4.3 插值与模板表达式
- 2.4.4 初识泛型
- 2.4.5 更新教师
- 2.4.6 测试中的路由
- 2.5 删除教师
- 2.6 收尾工作
- 2.6.1 RouterLink
- 2.6.2 fontawesome图标库
- 2.6.3 firefox
- 2.7 总结
- 第三章 用户登录
- 3.1 初识单元测试
- 3.2 http概述
- 3.3 Basic access authentication
- 3.4 着陆组件
- 3.5 @Output
- 3.6 TypeScript 类
- 3.7 浏览器缓存
- 3.8 总结
- 第四章 个人中心
- 4.1 原型
- 4.2 管道
- 4.3 对接后台
- 4.4 x-auth-token认证
- 4.5 拦截器
- 4.6 小结
- 第五章 系统菜单
- 5.1 延迟及测试
- 5.2 手动创建组件
- 5.3 隐藏测试信息
- 5.4 规划路由
- 5.5 定义菜单
- 5.6 注销
- 5.7 小结
- 第六章 班级管理
- 6.1 新增班级
- 6.1.1 组件初始化
- 6.1.2 MockApi 新建班级
- 6.1.3 ApiInterceptor
- 6.1.4 数据验证
- 6.1.5 教师选择列表
- 6.1.6 MockApi 教师列表
- 6.1.7 代码重构
- 6.1.8 小结
- 6.2 教师列表组件
- 6.2.1 初始化
- 6.2.2 响应式表单
- 6.2.3 getTestScheduler()
- 6.2.4 应用组件
- 6.2.5 小结
- 6.3 班级列表
- 6.3.1 原型设计
- 6.3.2 初始化分页
- 6.3.3 MockApi
- 6.3.4 静态分页
- 6.3.5 动态分页
- 6.3.6 @Input()
- 6.4 编辑班级
- 6.4.1 测试模块
- 6.4.2 响应式表单验证
- 6.4.3 @Input()
- 6.4.4 FormGroup
- 6.4.5 自定义FormControl
- 6.4.6 代码重构
- 6.4.7 小结
- 6.5 删除班级
- 6.6 集成测试
- 6.6.1 惰性加载
- 6.6.2 API拦截器
- 6.6.3 路由与跳转
- 6.6.4 ngStyle
- 6.7 初识Service
- 6.7.1 catchError
- 6.7.2 单例服务
- 6.7.3 单元测试
- 6.8 小结
- 第七章 学生管理
- 7.1 班级列表组件
- 7.2 新增学生
- 7.2.1 exports
- 7.2.2 自定义验证器
- 7.2.3 异步验证器
- 7.2.4 再识DI
- 7.2.5 属性型指令
- 7.2.6 完成功能
- 7.2.7 小结
- 7.3 单元测试进阶
- 7.4 学生列表
- 7.4.1 JSON对象与对象
- 7.4.2 单元测试
- 7.4.3 分页模块
- 7.4.4 子组件测试
- 7.4.5 重构分页
- 7.5 删除学生
- 7.5.1 第三方dialog
- 7.5.2 批量删除
- 7.5.3 面向对象
- 7.6 集成测试
- 7.7 编辑学生
- 7.7.1 初始化
- 7.7.2 自定义provider
- 7.7.3 更新学生
- 7.7.4 集成测试
- 7.7.5 可订阅的路由参数
- 7.7.6 小结
- 7.8 总结
- 第八章 其它
- 8.1 打包构建
- 8.2 发布部署
- 第九章 总结