如何处理反应式 Angular 形式的两个选择字段?

How to handle two selects fields in a reactive Angular form?

我有一个屏幕,我在其中使用反应形式动态创建元素,基本上我创建了卡片,其中每个卡片都有两个 selection 字段:

Scenario: 当我添加卡片和 select 布局时,该特定布局的选项加载到 select通过在 API 中创建过滤器的服务来获取资产留下相同的选项。

模板

<div class="card"
  formArrayName="scriptOperationOrders" 
  *ngFor="let workstation of formOperation.get('scriptOperationOrders')['controls']; index as idx"
>
  <div class="card-body" [formGroupName]="idx">
    <div class="form-row">
      <div class="form-group col-md-1">
        <label>Rank</label>
        <input type="text" name="rank" class="form-control" formControlName="rank"/>
      </div>
      <div class="form-group col-md-2">
        <label>Layout</label>
        <select formGroupName="layout" (ngModelChange)="searchAssetsByLayouts($event)">
          <option value="">Choose Layout</option>
          <option 
            *ngFor="let lay of (layouts$ | async)?.dataArray " 
            [value]="lay.id">{{ lay.description }}
          </option>
        </select>
      </div>
      <div class="form-group col-md-2">
        <label>Asset</label>
        <select formGroupName="asset">
          <option value="">Choose Asset</option>
          <option 
            *ngFor="let asset of (assets$ | async)?.dataArray " 
            [value]="asset.id">{{ asset.description }}
          </option>
        </select>
      </div>
    </div>
  </div>
</div>

控制器

layouts$: Observable<IResponse<ILayoutModel>>;
assets$: Observable<IResponse<IAssetModel>>;

ngOnInit() {
  ...
  this.buildFormOperation();
  this.layouts$ = this.layoutService.listLayouts();
  this.providers$ = this.providerService.listProviders();
}

buildFormOperation() {
  this.formOperation = this.fb.group({
    script: [],
    descriptionCode: [],
    description: [],
    scriptOperationOrders: new FormArray([])
  })
}

searchAssetsByLayouts(layoutId: number) {
  this.assets$ = this.assetService.listAssetsRoots(layoutId); // The assets$ variable is overridden here
}

资产列表服务

listAssetsRoots(layoutId?: number | string): Observable<IResponse<IAssetModel>> {
  return this.apiService.crudeList({
    url: `${this.url}/roots`,
    queryParams: {
      layoutId
    },
  })
  .pipe(map((res) => {
    return new IResponse<IAssetModel>(res, IAssetModel);
  }));
}

As you could be doing when selecting an option in the select layout, the options for that layout are loaded only in the select of assets on the same card

this.assets$ = this.assetService.listAssetsRoots(layoutId); as 这里覆盖了assets$变量
ts 文件:-

//declared what type of response is expected 
interface Assets{
  id:number,
  description :string
}
//initially set to empty
assets$ : Observable<Assets[]> = of([]);


//accepting second argument idx as row_index
 
 searchAssetsByLayouts(layoutId: number,row_index:number) {
  this.assets$[row_index] = this.assetService.listAssetsRoots(layoutId); // The assets$ variable is no more overridden
}

//html:-
//here used formControlName for 'layout' and 'asset' control insted of formGroupName
//and passed 'idx' as second parameter  to (ngModelChange)="searchAssetsByLayouts($event,idx)

<div class="card"
  formArrayName="scriptOperationOrders" 
  *ngFor="let workstation of formOperation.get('scriptOperationOrders')['controls']; index as idx"
>
  <div class="card-body" [formGroupName]="idx">
    <div class="form-row">
      <div class="form-group col-md-1">
        <label>Rank</label>
        <input type="text" name="rank" class="form-control" formControlName="rank"/>
      </div>
      <div class="form-group col-md-2">
        <label>Layout</label>
        <select formControlName="layout" (ngModelChange)="searchAssetsByLayouts($event,idx)">
          <option value="">Choose Layout</option>
          <option 
            *ngFor="let lay of (layouts$ | async)?.dataArray " 
            [value]="lay.id">{{ lay.description }}
          </option>
        </select>
      </div>
      <div class="form-group col-md-2">
        <label>Asset</label>
           <select formControlName="asset">
                  <option value="">Choose Asset</option>
                  <option 
                    *ngFor="let asset of (assets$[idx] | async)" 
                    [value]="asset.id">{{ asset.description }}
                  </option>
         </select>
      </div>
    </div>
  </div>
</div>