共计 5213 个字符,预计需要花费 14 分钟才能阅读完成。
本中要写到一个页面须要进行级联查问
以后修建是属于服务区下的,所以咱们抉择了服务区能力持续依据所抉择的服务区,也就是说如果咱们抉择完 服务区一,再抉择修建一,如果咱们此时更换抉择的服务区里所该当应该去除所抉择的修建。
依照之前的逻辑写的话只有在传入新的服务区后获取到对应的修建从而更改抉择列表项,所选内容就会主动重置为空,如下所示:
@Input() | |
set serviceAreaId(serviceId: number) {this.buildingId.setValue(null); | |
if (Number.isInteger(serviceId)) {this.listOfOption = []; | |
this.serviceAreaService.getAllBuildingByServiceAreaId(serviceId) | |
.subscribe(buildings => { | |
this.buildings = buildings; | |
buildings.forEach(building => { | |
this.listOfOption.push( | |
{ | |
label: building.name, | |
value: building.id | |
} | |
) | |
}) | |
}) | |
} else {this.listOfOption = []; | |
} | |
} |
然而这在 <thy-custom-select> 中并不实用,也就是说就算列表曾经更新然而并不会重置或是删除所选我的项目。这很显著不合乎咱们的需要,所以首先就是要找官网文档中有没有给出调用清空所选项的 API。
thy-custom-select 官方网站
然而很惋惜,并没有给出清空选项的 API,那么就只能找其余方法。
起初认为是子组件没有及时从新渲染导致的,起初依据这些关键词搜寻,并尝试在其获取完数据后对其进行从新渲染,然而并没有作用。
constructor(private serviceAreaService: BuildingService, | |
private cdr: ChangeDetectorRef) { } | |
this.serviceAreaService.getAllBuildingByServiceAreaId(serviceId) | |
.subscribe(buildings => { | |
this.buildings = buildings; | |
buildings.forEach(building => { | |
this.listOfOption.push( | |
{ | |
label: building.name, | |
value: building.id | |
} | |
) | |
}) | |
// 数据绑定变更的时候用 ChangeDetectorRef 驱动 angular 更新视图 | |
this.cdr.markForCheck(); | |
this.cdr.detectChanges();}) |
之后尝试改为 angular 原生的抉择组件,尽管能够实现想要的成果,然而款式与 <thy-custom-select> 有差异,格调不对立
<select [formControl]="buildingId" class="form-control"> | |
<option [ngValue]="null"> 请抉择 </option> | |
<option *ngFor="let building of buildings" [ngValue]="building.id"> | |
{{building.name}} | |
</option> | |
</select> |
起初又想到了一种更加简便间接的办法,子组件是依据 *ngif 来判断是否调用的,只有在在服务区抉择扭转时勾销其显示(即销毁目前子组件)并且在很短的提早后从新让其显示(即依据服务区新建子组件)便能够达到咱们想要的成果;
ngOninit(): void { | |
. . . | |
this.queryForm.get(this.formKeys.serviceArea)?.valueChanges | |
.subscribe(()=> {this.resetChildForm(); | |
} | |
) | |
} | |
resetChildForm(){ | |
this.showBuildingSelect= false; | |
setTimeout(() => {this.showBuildingSelect = true}, 10); | |
} |
<div class="ml-10" *ngIf="queryForm.get(formKeys.serviceArea)?.value && showBuildingSelect"> | |
<app-building-select [serviceAreaId]="queryForm.get(formKeys.serviceArea)?.value" [formControlName]="formKeys.buildingId"></app-building-select> | |
</div> |
然而这种写法的毛病就是可读性不高,并且集成度不高即调用完抉择组件还须要这些来配合应用,然而思考到应用这种查问形式的中央并不多,这样解决也能够承受。
第二个问题
应用场景 =》修建新建
如图所示咱们次要须要解决的问题就是如何解决分部工程的传值,首先是如何实现抉择框抉择状况的传递。
咱们此处是间接取得所有的分部工程模板而后让用户进行抉择,也就是说条数不是固定的,那么这也就不能用咱们所相熟的 form 表单传值。就算解决了这方面的问题还须要思考其从属的多构造的抉择状况是否传递过去。
对于抉择框的解决参考了之前我的项目的解决办法:每个抉择框都是一个组件,全选框是另一个组件,通过在前台实体中退出”是否被选中“属性来实现在提交时提交被选中的分部工程。
单选:
父组件:
<app-check-single [checked]="divisionalWorksTemplate._checked" | |
(beChange)="onSingleChange($event,divisionalWorksTemplate)"> | |
</app-check-single> |
onSingleChange($event: boolean, divisionalWorksTemplate: DivisionalWorksTemplate) { | |
divisionalWorksTemplate._checked = $event; | |
// 用于告诉全选组件选项的变动 | |
this.singleCheckboxChangeSubject.next();} |
子组件:
@Input() | |
set checked(checked: boolean) {this.formControl.setValue(checked); | |
} | |
@Output() | |
beChange = new EventEmitter<boolean>(); | |
formControl = new FormControl(false); | |
constructor() {} | |
ngOnInit(): void { | |
this.formControl.valueChanges | |
.subscribe(value => {this.beChange.emit(value); | |
}); | |
} |
明确各个参数的性能后整个组件就很好了解了,当咱们点击抉择时子组件检测到 formcontrol 的变动就会向父组件弹射表单的 Value 父组件接管到弹射就会扭转列表中分部工程的 _checked
字段为弹射值,从而使父组件得悉该项已被选中 / 勾销选中。
并且告诉全选组件来及时更改本身的状态即如果咱们选中了所有选项全选应该主动被选中,否则全选应不被选中。
而对于全选组件则是和单选原理雷同,不同的是全选组件传入了所有的分部工程而不是一个,从而实现对所有单选框状态的管制。此处就不再开展阐明,并且原我的项目中起初将这些组件改为了指令,待理解指令后再认真阐明。
之后咱们要解决的问题就是如何做到多构造的抉择,很显著这里也不能采纳 formcomtrol 进行绑定,所以仍是采取了单选组件的解决办法——在前台实体中退出以下类型来获取抉择状况。
/** | |
* 所抉择的分部工程类型 | |
*/ | |
_checkedDivisionalWorksType: DivisionalWorksType[] |
解决形式同单选组件,当选项值扭转时弹出值,将所选选项退出到 _checkedDivisionalWorksType
中。
之后值得说的就是提交时的解决:
此处须要解决的问题是从下面的图片中咱们也能够看到有些分部工程没有多构造,他们实际上固定有一个多构造,构造为默认。然而咱们在抉择时疏忽了他们,这也就导致如果齐全依照_checkedDivisionalWorksType 来解决的话很显著是不合理的,所以要对筛选进去的被抉择的分部工程进行进一步的筛选从而使其失常解决这些无多构造的构造工程并且当咱们没有对存在多构造的构造工程抉择然而却抉择了此构造工程的状况作出解决。
onSubmit(formGroup: FormGroup, divisionalWorksTemplates: DivisionalWorksTemplate[]) { | |
// 是否容许被提交,默认为 true | |
let permit = true; | |
// 所要提交的分部工程列表 | |
const checkedDivisionalWorksTemplates = [] as DivisionalWorksTemplate[]; | |
divisionalWorksTemplates.forEach((value) => {if(value._checked) {let checkedDivisionalWorksTemplate = {} as DivisionalWorksTemplate; | |
checkedDivisionalWorksTemplate.id = value.id; | |
if(value._checkedDivisionalWorksType && value._checkedDivisionalWorksType?.length !=0) { | |
// 当选择项不为空时将选择项赋给咱们要提交的构造工程 | |
checkedDivisionalWorksTemplate.divisionalWorksType = value._checkedDivisionalWorksType; | |
} else if(value.divisionalWorksType[0].structure === STRUCTURE.default.value && value.divisionalWorksType?.length === 1){ | |
// 当抉择我的项目为空然而其抉择总我的项目仅有一条并且为默认项时将总项赋给咱们要提交的构造工程 | |
checkedDivisionalWorksTemplate.divisionalWorksType = value.divisionalWorksType; | |
} else { | |
// 其余状况则为抉择我的项目为空然而总项有多个,弹出谬误领导用户为其配置具体构造 | |
this.notifyService.error('新增失败', "请为分部工程" + value.name +"抉择具体构造"); | |
// 不容许提交 | |
permit = false; | |
} | |
// 将查看合格项退出所要提交的分部工程列表中 | |
checkedDivisionalWorksTemplates.push(checkedDivisionalWorksTemplate); | |
} | |
}) | |
if(permit) {const newBuilding = {} as Building; | |
const serviceArea = {id: formGroup.get(this.formKeys.serviceArea)?.value | |
} as ServiceArea | |
newBuilding.name = formGroup.get(this.formKeys.name)?.value; | |
newBuilding.serviceArea = serviceArea; | |
newBuilding.divisionalWorksTemplate = checkedDivisionalWorksTemplates; | |
this.buildingService.save(newBuilding) | |
.subscribe((value) => {this.notifyService.success("新增胜利"); | |
this.isFinish.emit(value); | |
}, (error) => {this.notifyService.error("新增失败", error); | |
}) | |
} | |
} |
这些办法次要的思维就是通过前台实体自身来进行传值从而使得咱们能够进行如上这种模式的输出,并且不须要 form 绑定。
然而下面的做法尽管能够达成想要成果然而因为没有和 formcontrol 进行绑定,所以只能在提交时查看是否合乎提交条件,若不合乎则给出相应提醒,而咱们想要的是和其余信息输出时一样,在提交前就能够得悉所提交信息是否合格并给出提醒并且提交按钮为 disable。
等我的项目根本实现后仍需进行改变。