WEB全棧工程師視頻回放 (34.2)——Angular 雙向數據綁定 (ngModel)應用

應用場景
image.png

在視頻回放的第 34 講 34.2 節, 講了Angular 雙向數據綁定 (ngModel)的應用。 在工程示例中,出現了一個詭異的現象, 就是 child component 的編輯數據與 parent component 列表的數據出現了同步,正常情況下,應該是只有點擊 “添加商品”后, 商品列表才會更新, 這是什么原因造成的呢?

為什么出現錯誤的判斷?

既然是雙向數據綁定, 就意味著只要數據發生變化,就會觸發相應的onChange事件, 由此下意識地得出結論: 是 ngModel 造成的, 從而對 ngModel進行了批判。接著對工程進行了改造, 用 模板引用變量(template reference variable)解決了這個問題。 問題是解決了,但問題產生判斷真正原因真的是 ngModel 造成的嗎?

問題解讀與剖析

// product-create.component.ts 
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Product } from "../product";

@Component({
  selector: 'app-product-create',
  templateUrl: './product-create.component.html',
  styleUrls: ['./product-create.component.css']
})
export class ProductCreateComponent implements OnInit {

  @Output()  created = new EventEmitter<Product>();
  product : Product;
  constructor() { 
    this.product = new Product;
  }
  ngOnInit() {
  }
  createProduct( ){
    this.created.emit( this.product );
    console.log("子組件發射的數據=",this.product ); 
  }
}

既然懷疑是 ngModel 觸發的, 那么,在 createProduct() 方法中,添加一個log,如下:

createProduct( ){
this.created.emit( this.product );
console.log("子組件發射的數據=",this.product );

}

重新運行。 在創建商品的編輯框中,編輯數據時,發現 在瀏覽器的console中,數據并沒有發生變化,這說明, ngModel 在數據變化時,沒有觸發 createProduct( ) 方法。

找到真正原因

出現bug, 調試是最好的方法。 商品(product) 存放在一個數組中, log 如下:

image.png

前4項是初始化的商品列表, 從第5項開始,是新添加的商品。

發現一個奇怪的現象: 這個商品列表數組存放的是 Product,也就是說,存放了一個新添加的對象,而這個對象正是 ngModel 對象

import { Component, OnInit } from '@angular/core';
import { Product } from "../product";
@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {

  products: Product[];
  myProduct: any; 
  constructor() {
    this.products = new Array <Product>();    // 必須的,否則報錯, 創建對象的實例
   }
  ngOnInit() {
    this.products = [
      { title: "第 1 件商品", price: 11 },
      { title: "第 2 件商品", price: 22 },
      { title: "第 3 件商品", price: 33 },
      { title: "第 4 件商品", price: 44 },
      { title: "第 5 件商品", price: 55 },
    ];
    }

  addProduct( product: Product ){
   this.products.push(product);
  console.log("收到了來自 child 組件的數據",this.products);
   }

}

關鍵代碼:

addProduct( product: Product ){
this.products.push(product);
}

真正的原因在于:

子組件 發射的對象是:

this.created.emit( this.product );

父組件 接收到這個product 對象后, 進行了壓棧 ,如下:
> this.products.push(product);

解決方案

不再存儲這個與 ngModel 關聯的對象,而是重新構建一個Product 對象, 代碼改造如下:

// product-list.component.ts
addProduct( product: Product ){
    this.myProduct = {
    title :  product.title,
    price:  product.price
   }
   this.products.push( this.myProduct );
}

運行測試,之前的詭異現象不見了:

image.png

小結

用到 ngModel 時, 要特別注意。 從以上代碼可以看出, ngModel 的雙向數據綁定,是建立在一個共享內存(地址)的基礎之上的。 所以才出現,一變俱變!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容