Angular 4:如何处理级联变化?

时间:2017-04-22 18:39:04

标签: angular

我有一个小应用here

它的作用:它有3个下拉列表,表示地址选择 - 区,市和结算。它们相互依赖,因此在一个下拉列表中选择的内容决定了下一个下拉列表中的项目。有一个根组件将3个输入数字值传递给子组件(我还添加了一些延迟来模拟http调用)。

我的目标:为了能够立即更新根组件中的值,只要子组件发生变化(在AngularJS 1中,我们对子指令有=选项范围)。这就是为什么我对属性使用双向绑定的原因,你可以看到我必须在发生变化时发出。我还希望将数据作为简单的数字属性传递,而不是将子组件绑定到具有3个属性的某个自定义类。

我遇到的问题
1)每当有变化时我都必须通过EventEmitter<numner>手动发出(因为我有3个简单类型的属性)。 我们没有在AngularJS 1中做到这一点,那么有更灵活的解决方案吗?
2)您看到的应用有效,因为我在enableProdMode文件中添加了对main.ts的调用。那是因为我需要违反NG4 +的单向流规则:当一个下拉列表中的值发生变化时会发生这种情况,然后我需要将相关值设置为null并更新OnChanges钩子中依赖下拉列表中的项目(例如,当我改变地区时,市政当局必须无效)。 是否有更好的方法来执行此操作,或者可以违反规则,知道自己在做什么?

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

首先,我不会保留三个单独的数字,而是为它创建一些包装(让我们暂时将其称为wrapper - 请记住来自Rest的调用你应该收到一个对象与领域)

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

我们可以简化我们的子组件: 当我们输入wrapper对象时,我们不能将我们的逻辑基于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时遇到了问题(所以并不是所有的下拉都会自动更新,但希望你能感觉它应该如何工作)