如何处理反应式 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>
我有一个屏幕,我在其中使用反应形式动态创建元素,基本上我创建了卡片,其中每个卡片都有两个 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>