2017-04-22 57 views
2

我有一個小應用程序here
Angular 4:如何處理級聯變化?

它做什麼:它有3個下拉表示地址選擇 - 區,市政府和解決辦法。他們互相依賴,因此在下拉菜單中選擇的內容決定了下一個下拉菜單中的項目。有一個根組件將3個輸入數字值傳遞給子組件(我也添加了一些延遲來模擬http調用)。

我的目標:爲了能夠在根組件立即更新值,只要東西在子組件的變化(在AngularJS 1,我們對孩子的指令範圍=選項)。這就是爲什麼我對屬性使用雙向綁定的原因,您可以看到只要發生了某些變化就必須發出。我還希望將數據作爲簡單數字屬性傳遞,而不是將子組件綁定到具有3個屬性的某個自定義類。

我面對的問題是:
1)I具有每當有新的變化來手動通過EventEmitter<numner>發射(因爲我有3個簡單類型屬性)。 我們不需要在AngularJS 1中這樣做,那麼是否有比這更靈活的解決方案?
2)您看到的應用程序有效,因爲我在main.ts文件中添加了對enableProdMode的調用。這是因爲我需要違反NG4 +的單向流動規則:這發生在一個下拉列表中的值發生變化時,我需要將依賴值設置爲null並更新OnChanges掛鉤中相關下拉列表中的項目(例如,當我更改區,市必須無效)。 有沒有更好的方法來做到這一點,或者可以違反知道你在做什麼的規則?

回答

1

我在我的應用程序中有兩個下拉菜單,這些下拉菜單也依賴於對方。我使用的反應形式和訂閱價值變動:

slots$: Observable<Array<SlotIdentity>>; 


ngOnInit(): void { 
    this.buildRoleForm(); 

    this.slots$ = this.formGroup.get('pageId') 
    .valueChanges 
    .map(pageId => _.sortBy(this.pages.find(({id}) => id === +pageId).slots, 'slotNumber')) 
    .do(() => this.formGroup.get('slotId').setValue('')); 
} 

private buildRoleForm() { 
this.formGroup = this.formBuilder.group({ 
    pageId: ['', Validators.required], 
    slotId: ['', Validators.required] 
}); 

}

HTML是在這裏:

<form [formGroup]="formGroup" novalidate> 
    <div class="row"> 
    <div class="col-sm-6"> 
     <label for="pageNumber" col-sm-6>Page#</label> 
     <select id="pageNumber" class="form-control" formControlName="pageId"> 
     <option *ngFor="let page of pages" value="{{page.id}}"> 
      {{page.pageNumber}} 
     </option> 
     </select> 
    </div> 

    <div class="col-sm-6"> 
     <label for="slotNumber">Slot#</label> 
     <select id="slotNumber" class="form-control" formControlName="slotId"> 
     <option *ngFor="let slot of slots$ | async" value="{{slot.id}}"> 
      {{slot.slotNumber}} 
     </option> 
     </select> 
    </div> 
    </div> 
</form> 
+0

我不知道Reactive Forms的細節,但這是一個有趣的例子。 –

0

首先我不會遵守三個獨立的數字,而是創造一些包裝器它(讓我們暫時稱之爲wrapper - 記住從休息電話你應該收到一個領域的對象)

export class Wrapper { 
    districtId: number; 
    municipalityId: number; 
    settlementId: number; 
    constructor(dist, mun, sett){ 
     this.districtId = dist; 
     this.municipalityId = mun; 
     this.settlementId = sett; 
    } 
} 

那麼我們app.html看起來像:

District id: {{ wrapper.districtId }} 
Minicipality id: {{ wrapper.municipalityId }} 
Settlement id: {{ wrapper.settlementId }} 

<my-child [wrapper]="wrapper"></my-child> 

說明該領域的每一次變化都會自動在wrapper.districtId

可見,我們可以簡化我們的子組件: 當我們輸入我們不能將我們的邏輯基於OnChanges()(因爲它會被稱爲一旦對象變化引用了wrapper,在我們的例子中只有字段被更新),但是我們可以調用select上的特定函數變化:

<div> 
    <label for="district">District</label> 
    <select id="district" (change)="setMunicipalities()" [(ngModel)]="wrapper.districtId"> 
     <option [value]="district.id" *ngFor="let district of districts">{{ district.name }}</option> 
    </select> 
</div> 

和最終邏輯。請注意,當我們調用setMunicipalities()我們並不需要檢查是否有任何改變,請注意,我們沒有額外的檢查有什麼改變(如前)

constructor(private changeDetector: ChangeDetectorRef) { 
     this.districts = DISTRICTS; 
} 

ngOnInit() { 
    this.setMunicipalities(); 
    this.setSettlements(); 
}  


private setMunicipalities() { 
    this.municipalities = MUNICIPALITIES.filter(mun => mun.districtId == this.wrapper.districtId); 
    this.setSettlements(); 

    this.changeDetector.detectChanges(); 
} 

private setSettlements(){ 
    this.settlements = SETTLEMENTS.filter(sett => sett.municipalityId == this.wrapper.municipalityId); 
} 

我叉你plunker(https://plnkr.co/edit/A7aGJcZhQAryvVPLTrOA?p=preview) - 我有在plunker中注入ChangeDetectorRef的問題(所以不是所有的下拉列表都會自動更新,但希望你有這種感覺)

+0

好的,所以我在這裏添加了另一個分支:https://plnkr.co/edit/xIdEx1m3HWxMn9aLTdk1?p =預覽。我沒有使用ChangeDetectorRef,但它工作正常。你爲什麼要注入它?請注意,我仍然有一些邏輯來取消使用2個標誌的依賴值 - 否則我無法知道這些更改是否來自OnChanges(如果在示例中存在延遲時需要)或者從下拉列表的更改事件(在這種情況下,我真的需要取消該值)。只是爲了引導您瞭解示例,實際在fork中使用的所有組件在名稱中都有2個。 –

+0

我想使用ChangeDetectorRef手動觸發屏幕上的變化(但它沒有它,很好)。我沒有找到你提出的那些標誌的真實用例。在plunker的情況下,唯一的一個例子是當你還沒有在OnChanges塊中得到的AddressInfo時,子組件的初始化。然後,您可以執行setMunicipalities(),更新市政當局並將this.address.municipalityId始終設置爲null,然後繼續執行setSettlements()。當你輸入setMunicipalities()時,你應該總是清除下拉菜單。 – pezetem

+0

看看https://plnkr.co/edit/vqgcAkBYXPILCD3iKldc?p=preview另一方面我建議稍微不同的解決方案,讓我們等待,直到AddressInfo從一些Rest調用中解析出來,然後像這樣渲染Child組件:https: //plnkr.co/edit/aIBbIpogahc2AIVtg2EQ?p=preview – pezetem