Angular實戰記錄
阿新 • • 發佈:2018-01-27
rms ted 通過 enc 對象 pic 創建 form ble
當ngModel雙向綁定非基本數據類型值時
子組件中ngModel綁定的值改變時,通過onChangeCallback 傳回父組件時,有兩種情況:
- 基本數據類型:string/number 等變量,父組件中會跟著變化
- 非基本數據類型:{}/[]/Date/... 父組件中不會檢測到變化
解決方法:
創建一個新對象傳回:
this.onChangeCallback(new Date(this.date));
(順便完善父子組件間雙向數據綁定的實現)
子組件ts:
import { Component,forwardRef} from ‘@angular/core‘; import { ControlValueAccessor,NG_VALUE_ACCESSOR, DefaultValueAccessor } from ‘@angular/forms‘; @Component({ selector: ‘iq-timepicker‘, templateUrl: ‘timepicker.component.html‘, providers:[{ provide:NG_VALUE_ACCESSOR, useExisting:forwardRef(()=>TimePickerComponent), multi:true }] }) export class TimePickerComponent implements ControlValueAccessor{ private date:Date; private onChangeCallback: any = {}; private onTouchedCallback: any = {}; private triggerChange(){ //此時子組件中 this.date 已變化 let d = new Date(this.date); this.onChangeCallback(d);//變化傳給父組件 } ... writeValue(value: Date) { if(!value){ this.date=new Date(); }else{ this.date = new Date(value); } } registerOnChange(fn) { this.onChangeCallback = fn; } registerOnTouched(fn) { this.onTouchedCallback = fn; }
父組件html中使用:
<iq-timepicker [(ngModel)]="timeVariable"></iq-timepicker>
父組件向子組件傳值
方式:
- 屬性輸入 @Input()
- 雙向綁定 writevalue
註意:
- 傳入順序,先Input後writevalue
兩者當傳值為非基本數據類型時,都無法監測改變
Input方式:@Input() set 方法 或者 ngOnChanges,都無法監測改變。像這樣:
//子組件 import { Component, OnInit, Input, OnChanges,SimpleChanges } from ‘@angular/core‘; @Component({ selector: "NB-new-list", templateUrl: ‘...‘, styleUrls: [‘...‘] }) export class NBNewListComponent implements OnInit,OnChanges { @Input() currency;//幣種(此時是基本數據類型) ngOnChanges(changes: SimpleChanges){ if(changes["currency"]){//幣種 變化 //變化前的值:changes["currency"].previousValue //變化後的值:changes["currency"].currentValue ... } } }
解決方法:
可在生命周期ngDoCheck中監測變化:
//子組件 import { Component, OnInit, Input, DoCheck } from ‘@angular/core‘; @Component({ selector: "NB-new-list", templateUrl: ‘...‘, styleUrls: [‘...‘] }) export class NBNewListComponent implements OnInit { beforeList;//暫存上一個清單數據 @Input() purchaseData=[];//清單數組(此時是非基本數據類型) ngDoCheck(){ if (JSON.stringify(this.purchaseData) != JSON.stringify(this.beforeList)) {//當清單變化 this.beforeList = JSON.parse(JSON.stringify(this.purchaseData)); ... } } }
註意:
在ngDoCheck中進行input傳入值的前後比較時,如果是比較長的對象或數組,建議把上一個值保存為字符串,否則有些變化無法檢測到
形如:
ngDoCheck() {
if (JSON.stringify(this.purchaseData) != this.beforeListStr){//采購清單 變化
this.beforeListStr = JSON.stringify(this.purchaseData);
}
}
某些有用的生命周期
- ngDoCheck:可監測每次input傳參對象改變,例子如上
ngAfterViewChecked:每次完成界面渲染
使頁面強制刷新
如同AngularJS中的$apply()
使用如下:
import { ChangeDetectorRef} from ‘@angular/core‘;
@Component({
selector: "...",
templateUrl: ‘...‘,
styleUrls: [‘...‘]
})
export class ..Component implements OnInit {
constructor(private changeDetectorRef:ChangeDetectorRef) {
}
Fun(){
this.changeDetectorRef.detectChanges();//需要強制刷新
}
}
當select下拉選項變化時
有種情況,在同一個頁面,其他操作導致select的下拉選項發生變化,不刷新頁面。
此時需要重置已選的項:
- 已選的項沒有刪除,保持選中狀態
- 已選的項刪除,則置為”請選擇”
實現難點:
- 當獲取新的下拉列表時,需強制刷新界面;
- 當判斷已選的項目回來時,不僅需要設置雙向綁定的值val,還要重置 select對象的已選index和顯示text
html:
<tr *ngFor="let item of procurementList;index as i">
<td>
<select [(ngModel)]="item.MaterialSource" id="materialSource{{i}}" name="materialSource{{i}}" ngModel required>
<option value=‘‘>請選擇</option>
<option *ngFor="let em of contractList" [ngValue]="em.id">{{em.value}}</option>
</select>
</td>
</tr>
ts:
import { Component, OnInit, DoCheck,ChangeDetectorRef} from ‘@angular/core‘;
declare var $:any;
@Component({
selector: "...",
templateUrl: ‘...‘,
styleUrls: [‘...‘]
})
export class ..Component implements OnInit {
procurementList;
contractList;//合同列表(下拉列表數據)結構為{"id":"","value":""}...
constructor(private changeDetectorRef:ChangeDetectorRef) {
}
ngDoCheck(){
if (JSON.stringify(this.contractList) != window.localStorage.getItem("contractList")) {//合同列表變化
this.contractList = JSON.parse(window.localStorage.getItem("contractList"));
this.changeDetectorRef.detectChanges();//需要強制刷新
for(let i=0,len=this.procurementList.length;i<len;i++){
//重新檢查設置已選
let pro=this.procurementList[i];
let list=this.OnlyIdContract(pro["MaterialSource"]);
if(!list){
pro["MaterialSource"]="";//為請選擇
}else{
pro["MaterialSource"]=list["em"]["id"];//val
$("#materialSource"+i)[0].selectedIndex = list["index"]+1; //index
$("#materialSource"+i)[0].text=list["em"]["value"]; //text
}
}
}
}
OnlyIdContract(id){//根據合同唯一(id)標識 匹配合同項
let list={
em:"",//匹配下拉的項
index:""//匹配已選在現有列表中的index
}
let item;
for(let i=0,len=this.contractList.length;i<len;i++){
item=this.contractList[i];
if(item.id==id){
list.em=item;
list.index=i;
return list;
}
}
return "";//已選的已經不在合同列表中 則置空
}
}
Angular實戰記錄