本节我们完成教师管理中的最后一个功能模块 ---- 删除教师。 相对添加教师、编辑教师模块,删除教师相对要简单一些。删除功能直接集成在了教师列表模块中,仅仅作为教师列表App组件的功能出现。 接下来让我们共同实现教师的删除功能。 ## type定义类型 在上节中,大家完成了App组件`teachers`属性类型由`any`改写的工作,参考答案如下: 第一种方式: ```typescript +++ b/first-app/src/app/app.component.ts @@ -8,7 +8,12 @@ import {HttpClient} from '@angular/common/http'; }) export class AppComponent implements OnInit { // 初始化教师数组 - teachers = [] as any[]; + teachers = [] as { + name: string, + username: string, + email: string, + sex: true + }[]; constructor(private httpClient: HttpClient) { console.log(httpClient); @@ -18,7 +23,12 @@ export class AppComponent implements OnInit { * 组件初始化完成后将被自动执行一次 */ ngOnInit(): void { - this.httpClient.get<[]>('http://angular.api.codedemo.club:81/teacher') + this.httpClient.get<{ + name: string, + username: string, + email: string, + sex: true + }[]>('http://angular.api.codedemo.club:81/teacher') .subscribe(teachers => this.teachers = teachers); } } ``` 第二种方式: ```typescript +++ b/first-app/src/app/app.component.ts @@ -8,7 +8,7 @@ import {HttpClient} from '@angular/common/http'; }) export class AppComponent implements OnInit { // 初始化教师数组 - teachers = [] as any[]; + teachers = [] as Teacher[]; constructor(private httpClient: HttpClient) { console.log(httpClient); @@ -18,7 +18,17 @@ export class AppComponent implements OnInit { * 组件初始化完成后将被自动执行一次 */ ngOnInit(): void { - this.httpClient.get<[]>('http://angular.api.codedemo.club:81/teacher') + this.httpClient.get<Teacher[]>('http://angular.api.codedemo.club:81/teacher') .subscribe(teachers => this.teachers = teachers); } } + +/** + * 定义一个类型 + */ +type Teacher = { + name: string, + username: string, + email: string, + sex: true +}; ``` 教程中,我们基于第二种方式继续向下进行。 ## 触发方法 用户点击删除时,需要对应触发C层的方法来完成删除功能。Angular中每个html元素都添加了`click`事件,使用方法如下: ```html +++ b/first-app/src/app/app.component.html @@ -17,7 +17,7 @@ <td>{{ teacher.username }}</td> <td>{{ teacher.email }}</td> <td *ngIf="teacher.sex; else femaleBlock">男</td> - <td>删除</td> + <td (click)="C层对应的方法()">删除</td> </tr> </tbody> </table> ``` 此时当我们点击`td`元素时,则C对应的方法将被触发。比如我们在C层定义如下方法: ```typescript +++ b/first-app/src/app/app.component.ts @@ -21,6 +21,10 @@ export class AppComponent implements OnInit { this.httpClient.get<Teacher[]>('http://angular.api.codedemo.club:81/teacher') .subscribe(teachers => this.teachers = teachers); } + + onDelete(): void { + console.log('onDelete called'); + } } /** ``` 将`fdescript`移动到`src/app/app.component.spec.ts`中,并使用`ng t`启动系统: ![image-20210227181612793](https://img.kancloud.cn/b9/59/b959a7ea7d9ceddabf0a06672a4140c0_1130x344.png) 控制台发生了如上错误,它的意思是说当前测试模块并不认识`<router-outlet></router-outlet>`,解决该问题需要我们前面学习过的两个知识点: 1. 我们在前面提起过,提供`<router-outlet></router-outlet>`的provider为`RouterModule` 2. `RouterModule`仅用于`ng s`中,对应在单元测试`ng t`中应该使用`RouterTestingModule`来替换`RouterModule`. ```typescript +++ b/first-app/src/app/app.component.spec.ts @@ -1,12 +1,14 @@ import {TestBed} from '@angular/core/testing'; import {AppComponent} from './app.component'; import {HttpClientModule} from '@angular/common/http'; +import {RouterTestingModule} from '@angular/router/testing'; -describe('AppComponent', () => { +fdescribe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ - HttpClientModule + HttpClientModule, + RouterTestingModule ], declarations: [ AppComponent ``` ![image-20210227182101022](https://img.kancloud.cn/67/58/67585c86b2ae2276f325fe06eebfa3a0_2288x500.png) ## 对接后台 我们为大家提供的删除接口如下: ```bash DELETE /teacher/{id} ``` 将要删除教师的ID使用delete方法向后台发起请求则可以完成对应教师的删除功能。在请求所有教师时,后台同样携带了ID属性。 ```bash GET /teacher ``` | **类型Type** | **名称Name** | **描述Description** | **类型Schema** | | ------------ | ------------ | ------------------- | ------------------------------------------------------------ | | Response | | | `[{id: number, username: string, name: string, email: string, sex: boolean}, {...}]` | 我们在`Teacher`类型中增加ID属性,并将其应用到V层: ```typescript +++ b/first-app/src/app/app.component.ts @@ -31,6 +31,7 @@ export class AppComponent implements OnInit { * 定义一个类型 */ type Teacher = { + id: number, name: string, username: string, email: string, ``` ```html +++ b/first-app/src/app/app.component.html @@ -17,7 +17,7 @@ <td>{{ teacher.username }}</td> <td>{{ teacher.email }}</td> <td *ngIf="teacher.sex; else femaleBlock">男</td> - <td (click)="onDelete()">删除</td> + <td (click)="onDelete(teacher.id)">删除</td> </tr> </tbody> </table> ``` 然后继续在C层的onDelete方法中添加接收教师ID的参数: ```typescript +++ b/first-app/src/app/app.component.ts @@ -22,8 +22,8 @@ export class AppComponent implements OnInit { .subscribe(teachers => this.teachers = teachers); } - onDelete(): void { - console.log('onDelete called'); + onDelete(id: number): void { + console.log('onDelete called', id); } } ``` 如此以来,在V层点击`删除`时C层便可以接收到预删除教师的ID值。 ![image-20210227191537256](https://img.kancloud.cn/63/21/63212354b009daf7606e9b679fe97a13_852x230.png) 接下来我们完成删除功能: ```typescript +++ b/first-app/src/app/app.component.ts @@ -22,8 +22,11 @@ export class AppComponent implements OnInit { .subscribe(teachers => this.teachers = teachers); } - onDelete(): void { - console.log('onDelete called'); + onDelete(id: number): void { + const url = `http://angular.api.codedemo.club:81/teacher/${id}`; 👈 + this.httpClient.delete(url) + .subscribe(data => console.log('删除成功'), + error => console.log('删除失败', error)); } } ``` - 注意:我们在此使用是`` ` ``而非`'`,该按键在键盘上位于按键`1`的左侧。使用````` ``` 可以在其中以`${xxx}`的方式快速嵌入变量。`` `123${a}` `` 等价于`'123' + a`。👈 删除成功后调用`ngOnInit`方法重新请求数据: ```typescript +++ b/first-app/src/app/app.component.ts @@ -25,7 +25,7 @@ export class AppComponent implements OnInit { onDelete(id: number): void { const url = `http://angular.api.codedemo.club:81/teacher/${id}`; this.httpClient.delete(url) - .subscribe(data => console.log('删除成功'), + .subscribe(👉() => this.ngOnInit(), error => console.log('删除失败', error)); } } ``` - 👉 当请求没有返回值时,此处的参数留空即可,但不能省略`()` > **注意**:受后台限制,你无法删除ID为1,2的教师预留数据。 我们在Add组件中随意添加一个测试数据: ![image-20210227192648731](https://img.kancloud.cn/2a/8c/2a8ccd81b15d16c050a6a16fd6323776_2204x302.png) 然后点击其删除按扭后: ![image-20210227192753889](https://img.kancloud.cn/2e/a4/2ea4f5c9aab4a97cd73d44ddf8df83cb_2190x198.png) 测试成功。 ## 本节作业 1. 将前面章节中使用到字符串拼接变更为`` ` ` ``的形式。 2. 尝试删除教师张三、教师李四,并在控制台中查看错误。 | 名称 | 地址 | 备注 | | ------------------ | ------------------------------------------------------------ | ---- | | 绑定语法 | [https://angular.cn/guide/binding-syntax#binding-types-and-targets](https://angular.cn/guide/binding-syntax#binding-types-and-targets) | | | TypeScript高级类型 | [https://typescript.bootcss.com/advanced-types.html](https://typescript.bootcss.com/advanced-types.html) | | | 本节源码 | [https://github.com/mengyunzhi/angular11-guild/archive/step2.5.zip](https://github.com/mengyunzhi/angular11-guild/archive/step2.5.zip) | |