前面的章節中,我們完成了教師的查看列表index、新增add以及編輯edit的功能。本節中,我們在教師列表中增加`編輯`按鈕,用戶點擊該按鈕后跳轉到編輯界面,完成更新后再跳轉回教師列表界面;增加`新增`按鈕,點擊后跳轉至新增界面,完成新增后然后再回跳到列表界面。
**angular官方中文網把這種跳轉功能稱為`路由器鏈接`,對應的英文關鍵字為`router-links`,表示鏈接到某個路由。**
# 編輯按鈕
app.component.html
```html
<td>刪除</td> ?
<td><a routerLink="/edit/{{teacher.id}}">編輯</a> 刪除</td> ? ?
```
* ? 使用routeLink來聲明a標簽跳轉的地址,使用`{{teacher.id}}`來填充該teacher對象對應的id值
或者我們也可以這樣使用:
```html
<td><a [routerLink]="['/edit', teacher.id]">編輯</a> 刪除</td> ?
```
* ? 使用`[routerLink]`來替換`routerLink`,接收的值的類型為字符串,該字符串中標記了一個數組,數組的第一項為路由地址,第二項為路由參數。
> 在實際的項目中,當第一種方法無法滿足我們的需求時,我們采用第二種方法。
## 完成編輯后回跳
teacher-edit.component.ts
```js
import {ActivatedRoute, Router} from '@angular/router';
constructor(private route: ActivatedRoute,
private httpClient: HttpClient,
private appComponent: AppComponent,
private router: Router ①) {
}
/**
* 提交表單
*/
onSubmit(): void {
this.httpClient.put(this.getUrl(), this.teacher)
.subscribe(() => {
console.log('更新成功');
this.appComponent.ngOnInit();
this.router.navigate(['/']); ?
},
() => {
console.error(`更新數據時發生錯誤,url:${this.getUrl()}`);
});
}
```
* ① 引用Router。**注意:**前面我們引用的是`route 路由`,而現在我們引用的是`router 路由提供者`。
* ? 使用`router.navigate()`完成跳轉,該函數接收的參數類型為`數組`,在數組中第一項指跳轉的路由地址。
## 測試

測試中我們發現雖然實現了由列表頁向編輯頁進行跳轉,編輯完成后也的確是跳轉回了首頁。但是如果我們在編輯的頁面中點擊編輯按鈕時,雖然URL如期發生了變化(說明路由器鏈接是成功的),但編輯頁面的內容卻未發生任何變化。這明顯是一個BUG。
> 如果在軟件的測試過程中,你總能想出各種可能導致BUG的測試用例。這說明你足夠用心的同時天生就具備了軟件開發工程師的靈魂。
**為什么會這樣呢?**猜測原因的同時,我們增加些測試代碼:
teacher-edit.component.ts
```js
ngOnInit(): void {
console.log('組件初始化'); ?
this.httpClient.get(this.getUrl())
```
* ? 當組件被初始化時,在控制臺打印信息。

通過測試我們猜測:在進行組件調用時,如果當前的界面存在此組件,則直接使用此組件而不在重新渲染。所以當在編輯界面中編輯其它的數據時,教師編輯組件中的`ngOnInit`方法沒有被重新調用,導致了編輯界面中的數據未發生任何變化。此時可能你想到了在數據添加的小節中,我們添加完數據后教師列表頁并沒有實時的更新,最后我們使用的方法是在教師新增組件中注入了教師列表組件(AppComponent),并手動的調用了教師列表組件的`ngOnInit`方法(在教師編輯界面我們也是這么處理的)。同時,前面我們還講過可以在子組件中直接注入父組件,因為子組件依賴于父組件,子組件存在時說明父組件必然存在;但無法在父組件中注入子組件,因為父組件存在時子組件不一定存在,這就決定了我們無法用“在App組件中調用TeacherEdit組件中的ngOnInit來強制子組件執行該方法(實際上即使可能這樣做,也是無濟無事的)”。
在下個小節中,我們將使用一種新的設計思想 -- **觀察者模式**來解決這個問題。
# 參考文檔
| 名稱 | 鏈接 | 預計學習時長(分) |
| --- | --- | --- |
| 路由器鏈接 | [https://www.angular.cn/guide/router#router-links](https://www.angular.cn/guide/router#router-links) | 2 |
| 路由參數 | [https://www.angular.cn/guide/router#route-parameters](https://www.angular.cn/guide/router#route-parameters) | 5 |
| 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step2.4.6](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step2.4.6) | - |
- 序言
- 第一章:Hello World
- 第一節:Angular準備工作
- 1 Node.js
- 2 npm
- 3 WebStorm
- 第二節:Hello Angular
- 第三節:Spring Boot準備工作
- 1 JDK
- 2 MAVEN
- 3 IDEA
- 第四節:Hello Spring Boot
- 1 Spring Initializr
- 2 Hello Spring Boot!
- 3 maven國內源配置
- 4 package與import
- 第五節:Hello Spring Boot + Angular
- 1 依賴注入【前】
- 2 HttpClient獲取數據【前】
- 3 數據綁定【前】
- 4 回調函數【選學】
- 第二章 教師管理
- 第一節 數據庫初始化
- 第二節 CRUD之R查數據
- 1 原型初始化【前】
- 2 連接數據庫【后】
- 3 使用JDBC讀取數據【后】
- 4 前后臺對接
- 5 ng-if【前】
- 6 日期管道【前】
- 第三節 CRUD之C增數據
- 1 新建組件并映射路由【前】
- 2 模板驅動表單【前】
- 3 httpClient post請求【前】
- 4 保存數據【后】
- 5 組件間調用【前】
- 第四節 CRUD之U改數據
- 1 路由參數【前】
- 2 請求映射【后】
- 3 前后臺對接【前】
- 4 更新數據【前】
- 5 更新某個教師【后】
- 6 路由器鏈接【前】
- 7 觀察者模式【前】
- 第五節 CRUD之D刪數據
- 1 綁定到用戶輸入事件【前】
- 2 刪除某個教師【后】
- 第六節 代碼重構
- 1 文件夾化【前】
- 2 優化交互體驗【前】
- 3 相對與絕對地址【前】
- 第三章 班級管理
- 第一節 JPA初始化數據表
- 第二節 班級列表
- 1 新建模塊【前】
- 2 初識單元測試【前】
- 3 初始化原型【前】
- 4 面向對象【前】
- 5 測試HTTP請求【前】
- 6 測試INPUT【前】
- 7 測試BUTTON【前】
- 8 @RequestParam【后】
- 9 Repository【后】
- 10 前后臺對接【前】
- 第三節 新增班級
- 1 初始化【前】
- 2 響應式表單【前】
- 3 測試POST請求【前】
- 4 JPA插入數據【后】
- 5 單元測試【后】
- 6 惰性加載【前】
- 7 對接【前】
- 第四節 編輯班級
- 1 FormGroup【前】
- 2 x、[x]、{{x}}與(x)【前】
- 3 模擬路由服務【前】
- 4 測試間諜spy【前】
- 5 使用JPA更新數據【后】
- 6 分層開發【后】
- 7 前后臺對接
- 8 深入imports【前】
- 9 深入exports【前】
- 第五節 選擇教師組件
- 1 初始化【前】
- 2 動態數據綁定【前】
- 3 初識泛型
- 4 @Output()【前】
- 5 @Input()【前】
- 6 再識單元測試【前】
- 7 其它問題
- 第六節 刪除班級
- 1 TDD【前】
- 2 TDD【后】
- 3 前后臺對接
- 第四章 學生管理
- 第一節 引入Bootstrap【前】
- 第二節 NAV導航組件【前】
- 1 初始化
- 2 Bootstrap格式化
- 3 RouterLinkActive
- 第三節 footer組件【前】
- 第四節 歡迎界面【前】
- 第五節 新增學生
- 1 初始化【前】
- 2 選擇班級組件【前】
- 3 復用選擇組件【前】
- 4 完善功能【前】
- 5 MVC【前】
- 6 非NULL校驗【后】
- 7 唯一性校驗【后】
- 8 @PrePersist【后】
- 9 CM層開發【后】
- 10 集成測試
- 第六節 學生列表
- 1 分頁【后】
- 2 HashMap與LinkedHashMap
- 3 初識綜合查詢【后】
- 4 綜合查詢進階【后】
- 5 小試綜合查詢【后】
- 6 初始化【前】
- 7 M層【前】
- 8 單元測試與分頁【前】
- 9 單選與多選【前】
- 10 集成測試
- 第七節 編輯學生
- 1 初始化【前】
- 2 嵌套組件測試【前】
- 3 功能開發【前】
- 4 JsonPath【后】
- 5 spyOn【后】
- 6 集成測試
- 7 @Input 異步傳值【前】
- 8 值傳遞與引入傳遞
- 9 @PreUpdate【后】
- 10 表單驗證【前】
- 第八節 刪除學生
- 1 CSS選擇器【前】
- 2 confirm【前】
- 3 功能開發與測試【后】
- 4 集成測試
- 5 定制提示框【前】
- 6 引入圖標庫【前】
- 第九節 集成測試
- 第五章 登錄與注銷
- 第一節:普通登錄
- 1 原型【前】
- 2 功能設計【前】
- 3 功能設計【后】
- 4 應用登錄組件【前】
- 5 注銷【前】
- 6 保留登錄狀態【前】
- 第二節:你是誰
- 1 過濾器【后】
- 2 令牌機制【后】
- 3 裝飾器模式【后】
- 4 攔截器【前】
- 5 RxJS操作符【前】
- 6 用戶登錄與注銷【后】
- 7 個人中心【前】
- 8 攔截器【后】
- 9 集成測試
- 10 單例模式
- 第六章 課程管理
- 第一節 新增課程
- 1 初始化【前】
- 2 嵌套組件測試【前】
- 3 async管道【前】
- 4 優雅的測試【前】
- 5 功能開發【前】
- 6 實體監聽器【后】
- 7 @ManyToMany【后】
- 8 集成測試【前】
- 9 異步驗證器【前】
- 10 詳解CORS【前】
- 第二節 課程列表
- 第三節 果斷
- 1 初始化【前】
- 2 分頁組件【前】
- 2 分頁組件【前】
- 3 綜合查詢【前】
- 4 綜合查詢【后】
- 4 綜合查詢【后】
- 第節 班級列表
- 第節 教師列表
- 第節 編輯課程
- TODO返回機制【前】
- 4 彈出框組件【前】
- 5 多路由出口【前】
- 第節 刪除課程
- 第七章 權限管理
- 第一節 AOP
- 總結
- 開發規范
- 備用