我們往往把 `C層的數據自動向V層傳輸的機制`叫做`數據綁定`,把`V層數據自動C層傳輸的機制`也叫`數據綁定`。本節中討論`C -> V`的綁定機制。在Angular中C層向V層的數據綁定是隱性的:C層中聲明的屬性均被自動綁定到V層。
>[info] C層:app.component.ts;V層:app.component.html。
# 數據綁定
app.component.ts
~~~
export class AppComponent {
constructor(private httpClient: HttpClient) {
// 向8080端口的helloWorld路徑發起請求
httpClient.get('http://localhost:8080/helloWorld')
.subscribe(success, error);
}
title = 'hello-world'; ?
}
~~~
? C層定義了title屬性,則在V層中可以直接顯示該屬性的值。
# 數據顯示
app.component.html
```html
<h1 style="text-align: center; margin-top: 100px;">
{{title}}!?
</h1>
<router-outlet></router-outlet>
```
? V層中顯示綁定的數據title。
## 測試

# 在V層顯示后臺返回數據
想將后臺返回的數據綁定給V層,只需要改變C層中的`title`變量賦值就可以了。`title`的值改變會將會自動的更新顯示頁面中。
## 匿名函數
在處理后臺返回數據以前, 對原代碼進行稍許整理使其更符合通用的JS編程風格。
在JS中,我們可以在使用某個函數時,直接將函數定義在參考中,就好比:
app.component.ts
~~~
export class AppComponent {
constructor(private httpClient: HttpClient) {
// 向8080端口的helloWorld路徑發起請求
httpClient.get('http://localhost:8080/helloWorld')
.subscribe(
success, ?
error);
}
title = 'hello-world';
}
/**
* 在控制臺打印傳入值
* @param data 任意數據
*/
function success(data) { ?
console.log('請求成功');
console.log(data);
}
~~~
等價于
~~~
export class AppComponent {
constructor(private httpClient: HttpClient) {
// 向8080端口的helloWorld路徑發起請求
httpClient.get('http://localhost:8080/helloWorld')
.subscribe(
function success(data) { ?
console.log('請求成功');
console.log(data);
},
error);
}
title = 'hello-world';
}
~~~
?等于?,所以使用?替換?后,就變成了?。
以上代碼還等價于
~~~
export class AppComponent {
constructor(private httpClient: HttpClient) {
// 向8080端口的helloWorld路徑發起請求
httpClient.get('http://localhost:8080/helloWorld')
.subscribe((data) => { ?
console.log('請求成功');
console.log(data);
}, error);
}
title = 'hello-world';
}
~~~
由于?只會被用到1次,所以我們可以省略它的名字,便簡化為了?。在后續的教程中,我們會越來越多的使用這種方式。
## 我的點滴
時間回到20年前自己還剛剛上高中的時候,有一天了解到原來住校生有晚自習。帶著好奇的心情上了一晚上了,教室里無數展日光燈把環境照亮,那種感覺別提有多舒服了,突然感覺到晚上能有這么明亮的教室學習是一件非常幸福的事情。從那時候起,開始了走讀生的晚自習生活。晚自習會上到9點鐘,然后和同學騎自行車走到3公里的國道回家,那時候車比較少,到晚上的時候一般就是拉稻草的車或一些拉貨的四輪車,少許會有幾輛摩托車。
有一天自習完如常的和幾個同學(只記得王樂超一個了)一起回家,半路上突然發現路邊摔著一輛摩托車,預感到可能有事情發生后我們下車在摩托周圍開始找人,果然不遠處還躺著一個人。說實話那時候嚇壞了,人碰到這種事情老往最壞的地方想,我們嘗試著用手輕推了幾下并喊了幾下,最后發現人還活著于是問了電話號碼,然后分工合作:有同學守著他,而我和另外的同學則去村里找有電話號碼的人家趕快去給他家人打電話求助。只聽接到電話的那頭兩口子已經開始不淡定了,過了半小時左右他家人到了,發現原來是自己的鄰居家的小孩。。而恰好的是,這個有電話的人家前些天剛剛給自己的兒子買的摩托車。
把那人送上車后,我們幾個心里踏實的各回各家了。當初的那個人并不知道我們的名字,我們亦然。可能在后面的人生路上,我們還有過幾面之緣,也可能至此再也沒有見過,或者他后來一直就在我身邊。但這些都不重要,重要的事我們在幫助了他的時候,并不需要知道他的名字。
*****
在編程的世界里把這種情景的處理叫做**匿名函數**。
*****
在現實生活中,匿名函數太普遍了。比如今天我們坐地鐵來上班,我們并不知道地鐵司機的姓名,但這個妨礙他來駕駛地鐵這個事實;出了地換,你買早點時我沒有問題老板叫什么名字。或者正在學習教程的你,可能正處于河北工業大學的教室里,此時你可能都不知道授課教師的姓名。我們的生活中,有太多太多的才肩而過,一面之緣了。
> 我不知道你來自哪里,不知道你的過去,甚至于連你的姓名我都不知道,但這些都不重要,因為你活生生的就在這里! ---- 致`匿名函數`
# 賦值
app.component.ts
~~~
constructor(private httpClient: HttpClient) {
const self = this; ?
/* 向8080端口的helloWorld路徑發起請求 */
this.httpClient.get('http://localhost:8080/helloWorld')
.subscribe(
function success(data: { message: string }) { ?
self?.title = data.message;
console.log(data);
},
error);
}
~~~
* ? 常規寫法,此處的this表示為:本對象。所以此行代碼解釋為:self = 本App組件對象。
* ? 聲明`data`參數接收的類型。作用有兩個:其一為調用`自己`(指這個匿名方法)的方法規定了數據類型,指調用此方法向參考`data`傳值時,該值中必須有`message`字段且該字段的類型必須為`string`。其二是為`自己`在方法體內部使用`data`對象時提供類型參考。
* ? 設置**App組件對象**的title值為data.message
## 測試

# 主要數據流如下

# 本節小測
嘗試拋棄`self`而直接使用`this`,請測試看會發生什么,那么為什么會這樣呢?
app.component.ts
~~~
constructor(private httpClient: HttpClient) {
const self = this;
/* 向8080端口的helloWorld路徑發起請求 */
this.httpClient.get('http://localhost:8080/helloWorld')
.subscribe(
function success(data: { message: string }) {
this.title = data.message; ?
console.log(data);
},
error);
}
~~~
? 在這里直接使用this
## 上節答案
實現的方案有很多種,在此給出其中的兩種:
方案一:
~~~
class Yunzhi {
private input: string;
public get(input: string) {
this.input = input;
return this; ?
}
public subscribe(successFunction, errorFunction) {
if (this.input === 'a') {
successFunction('hello success');
} else {
errorFunction('hello error');
}
}
}
~~~
? 在get方法中,將`this 自己`做為了返回值。自己中存在?subscribe方法。
? 接收兩個參數,作者心里認為這兩個參數的類型是函數類型,所以在內部代碼執行了 `successFunction()`,`errorFunction()`。
方案二:
~~~
class Yunzhi {
public get(input: string) {
return new Observable(input); ?
}
}
class Observable { ?
private readonly input: string;
constructor(input: string) {
this.input = input;
}
public subscribe(successFunction, errorFunction) { ?
if (this.input === 'a') {
successFunction('hello success');
} else {
errorFunction('hello error');
}
}
},
~~~
? 在get方法中,返回了實例化`Observable`的對象?,該對象?存在?subscribe方法。
> 注意: 不是返回了`Observable`,而是返回了根據`Observable`實例化的對象。`Observable`是個圖紙、是個協議、是個功能需求描述,它是看不見摸不著的(抽象的)。根據此樓房圖紙蓋的樓房是對象,是看的見摸的著的;根據USB協議生產的USB鼠標是對象,是看的見摸的著的;根據用車需求提供的汽車是個對象,也是看的見也摸的著。
- 序言
- 第一章: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
- 總結
- 開發規范
- 備用