2017-04-22 22 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