参考上节的内容,我们按下面的步骤完成编辑功能前台的初始化操作: 1. 组件C层初始化。 2. 新建组件V层初始化。 3. 将组件添加到对应的模块中。 4. 建立路由与组件进行关联。 # 初始化 ## C层 和前面的增加数据组件的命名方式相似,我们将其命名为:teacher-edit.component.ts ```js import {Component, OnInit} from '@angular/core'; @Component({ templateUrl: './teacher-edit.component.html' }) export class TeacherEditComponent implements OnInit { ngOnInit(): void { } } ``` ## V层 teacher-edit.component.html ```html teacher edit! ``` 添加新文件后目录结构如下: ``` . ├── app-routing.module.ts ├── app.component.html ├── app.component.sass ├── app.component.spec.ts ├── app.component.ts ├── app.module.ts ├── teacher-add.component.html ├── teacher-add.component.ts ├── teacher-edit.component.html └── teacher-edit.component.ts ``` ## 组件添加到模块 app.module.ts ```js import {TeacherEditComponent} from './teacher-edit.component'; ➀ @NgModule({ declarations: [ AppComponent, TeacherAddComponent, TeacherEditComponent ➁ ], ``` > 使用“➀”来标记出文件变动的位置,同时说明该知识点前面的章节已经涉及过,此处不再重复讲解。 ## 路由 app-routing.module.ts ```js import {NgModule} from '@angular/core'; import {Routes, RouterModule} from '@angular/router'; import {TeacherAddComponent} from './teacher-add.component'; import {TeacherEditComponent} from './teacher-edit.component'; ➀ const routes: Routes = [ { path: 'add', component: TeacherAddComponent }, { ➊ path: 'edit', ➁ component: TeacherEditComponent ➂ } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } ``` * ➊ 在数组中添加新对象 ## 测试 ![](https://img.kancloud.cn/4e/c3/4ec35ee2e6f35a603ba1eed0cfd06b14_359x142.png) # 获取URL中的参数 在编辑数据前,我们需要通过`URL`来获取用户当前需要编辑教师的ID。比如用户需要编辑ID为1的教师,则`URL`应该是[http://localhost:4200/edit/1](http://localhost:4200/edit/1)或[http://localhost:4200/edit?id=1](http://localhost:4200/edit?id=1)或者更新新颖的[http://localhost:4200/edit;d=1](http://localhost:4200/edit;d=1)形式。 ## PATH模式 [http://localhost:4200/edit/1](http://localhost:4200/edit/1)是以后我们在项目中使用的最多,也是最常见的一种,定义路由及获取路由参数的方法相对较简单容易理解,我们又常称这种方法为`PATH模式`。 AppRoutingModule ```js const routes: Routes = [ { path: 'add', component: TeacherAddComponent }, { path: 'edit/:id', ➊ component: TeacherEditComponent } ]; ``` * ➊ 使用具体的id值来替换`:id`,即达到传入参数的目的。比如`edit/1`表示传入的`id`值为1 路由定义完成后,我们[http://localhost:4200/edit/1](http://localhost:4200/edit/1),并尝试在`TeacherEditComponent`中获取该`路由参数`的值。 ### 获取路由参数的值 teacher-edit.component.ts ```js import {Component, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; ➀ @Component({ templateUrl: './teacher-edit.component.html' }) export class TeacherEditComponent implements OnInit { constructor(private route: ActivatedRoute ➁) { } ngOnInit(): void { const id = this.route.snapshot.paramMap.get('id'); ➊ console.log(id); ➂ } } ``` * ➊ 调用路由对象的`快照`属性的`参数Map`属性的`get()`方法,传入要获取参数的关键字`id`来获取参数的值 ### 测试 ![](https://img.kancloud.cn/f7/ac/f7acf6aab8e7a96e795b6b55bac573b0_469x342.png) ## GET模式 在很多常的项目中,使用最常用的`get`方式在参数中使用`?key1=value1*key2=value2`的方法来进行传值仍然是首选。虽然我们并不推荐这么做,但某些特殊的情况下我们的确也需要借助该方法来传值。在`GET模式`,访问地址为:[http://localhost:4200/edit?id=1](http://localhost:4200/edit?id=1)。 ### 修改路由 app-routing.module.ts ```js { path: 'edit', ➊ component: TeacherEditComponent } ``` * ➊ 由`edit/:id`修正为`edit`。 ### 获取GET参数的值 teacher-edit.component.ts ```js ngOnInit(): void { const id = this.route.snapshot.queryParamMap.get('id'); ➊ console.log(id); } ``` * ➊ 由this.route.snapshot.`paramMap`.get('id');修正为this.route.snapshot.`queryParamMap`.get('id'); ### 测试 访问:[http://localhost:4200/edit?id=1](http://localhost:4200/edit?id=1) ![](https://img.kancloud.cn/da/f8/daf840247d77ee1899c1df3a939da6ee_432x341.png) ## 矩阵URL 另有一种URL写法是[http://localhost:4200/edit;d=1](http://localhost:4200/edit;id=1),它被称为`Matrix URL 矩阵URL`,写法首次提出是在[1996 提案](http://www.w3.org/DesignIssues/MatrixURIs.html)中,提出者是 Web 的奠基人:Tim Berners-Lee。在angular中,获取该参数值的方法同`PATH模式`相同。 TeacherEditComponent ```js ngOnInit(): void { const id = this.route.snapshot.paramMap.get('id'); ➀ console.log(id); } ``` ### 测试 ![](https://img.kancloud.cn/c3/d8/c3d87a6cfe90df70bc5ab467363d7a1f_372x343.png) # 本节作业 把路由恢复为`PATH`模式,并在V层中直接显示获取到的`id`的值。 **作业完成后请继续学习** # 定义请求接口规范 现在,我们可以为后台定义一个接口规范。然后将此规范发送给后台成员,最终待后台开发完成后完成对接了。在进行某个特定的数据请求时,我们会这样定义:方法`GET`、地址`资源名\资源ID`,比如此时我们需要定的接口地址为:方法:`GET`、地址:`Teacher\<id>`。 > `Teacher\<id>`表示,此地址需要被特定的`id`值覆盖且`id`为必选项,比如`id = 1`则此地址为:`Teacher\1`。 ## C层完成对接 由URL中获取到了教师的ID,并且刚刚也定义了请求的接口规范,此时我们便可以参考前面的小节完成模拟的数据请求了。 TeacherEditComponent ```js import {Component, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HttpClient} from '@angular/common/http'; ① @Component({ templateUrl: './teacher-edit.component.html' }) export class TeacherEditComponent implements OnInit { public teacher: any; constructor(private route: ActivatedRoute, private httpClient: HttpClient ②) { } ngOnInit(): void { const id = this.route.snapshot.paramMap.get('id'); const url = 'http://localhost:8080/Teacher/' + id; this.httpClient.get(url) ③ .subscribe((data) => { this.teacher = data; }, () => { console.log(`请求 ${url} 时发生错误`); ➋ }); } } ``` * ➊ 拼接请求地址 * ➋ 注意此时``console.log(`直接引用变量的字符串`)``中使用的是 `` ` `` (ESC下边、数字1左边、TAB上边那个以前或许没用过的按键),而不是 ` ' ` 。``console.log(`请求 ${url} 时发生错误`)`` 等价于`console.log('请求 ' + url + ' 时发生错误');` 为了提升开发的效率、降低开发的难度,此时在V层直接打印这个教师。 teacher-edit.component.html ```html <pre>{{teacher | json}}</pre> ``` ## 测试 ![](https://img.kancloud.cn/a3/a1/a3a115524a4a03ea81f9bc5c003043cb_588x430.png) > 在没有后台的情况下,注定会发生请求错语。 ## 总结 1. **paramMap**获取PATH模式下及矩阵模式下的传值,**queryParamMap**获取GET模式下的传值。 2. PATH模式下,需要在路由中定义参数名称;矩阵模式下及GET模式下,**不**需要在路由中定义参数名称。 # 参考文档 | 名称 | 链接 | 预计学习时长(分) | | --- | --- | --- | | *Snapshot*(快照):当不需要 Observable 时的替代品 | [https://www.angular.cn/guide/router#snapshot-the-no-observable-alternative](https://www.angular.cn/guide/router#snapshot-the-no-observable-alternative) | 2 | | 路由参数 | [https://www.angular.cn/guide/router#route-parameters](https://www.angular.cn/guide/router#route-parameters) | 3 | | 源码地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step2.4.1](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step2.4.1) | - |