如何以编程方式将属性设置为FormControl?

时间:2017-10-07 09:11:10

标签: angular angular2-forms angular2-formbuilder

大问题简短:基本上我想要实现的是将readonly属性应用于FormControl(文本框),就像以编程方式创建它一样。

完整方案: 我的Form有一个FormRow,其元素(FormGroup s)部分是动态生成的。我也可以选择在点击按钮时添加一行。

我希望动态生成的FormGroupFormControl s(文本框)为readonly,但手动添加的FormControl应该是可编辑的。

我怎样才能做到这一点?

<div formArrayName="rows">
    <div class="row" *ngFor="let row of detailForm.get('rows').controls; let i = index" [formGroupName]="i">
        <div class="col-xs-1 text-center">
            <input type="checkbox" [(ngModel)]="detailSelected[i]" [ngModelOptions]="{standalone: true}">
        </div>
        <div class="col-xs-2">
            <input type="text" class="form-control" formControlName="account" (change)="getAccountAssociatedDetails(detailForm.get(['rows', i, 'account']), 'account', i)">
        </div>
        <div class="col-xs-2">
            <input type="text" class="form-control" formControlName="detailNo" (change)="getAccountAssociatedDetails(detailForm.get(['rows', i, 'detailNo']), 'detail', i)">
        </div>
        <div class="col-xs-4">
            <input type="text" class="form-control" readonly formControlName="detailName">
        </div>
        <div class="col-xs-3">
            <input type="text" class="form-control" readonly formControlName="detailCountry">
        </div>
    </div>
</div>

change的文本框值上,我正在调用函数getAccountAssociatedDetails,如您所见。如果有一些与输入值相关的详细信息,我将替换当前的FormGroup并在行中添加更多FormGroup

getAccountAssociatedDetails(control: FormControl, type: string, index: number) {
    let value = control.value;
    if (!!value) {
        let form = this.detailForm;
        control.setErrors({
            'alreadyEntered': null
        });

        if (type === 'detail') {
            if (this.detailAlreadyEnteredManually.detailNo.includes(value)) {
                control.setErrors({
                    'alreadyEntered': true
                });
            }
        } else if (type === 'account') {
            if (this.detailAlreadyEnteredManually.accountNumber.includes(value)) {
                control.setErrors({
                    'alreadyEntered': true
                });
            }
        }

        // if detail or account is already entered dont call service
        if (!control.hasError('alreadyEntered')) {
            this.agreementDetailsService.getdetails(value, type)
                .subscribe(response => {
                        let associatedDetailsArray = < Array < any >> response;
                        if (!!associatedDetailsArray) {
                            let rows = < FormArray > form.get('rows');

                            // if search mode is 'detail'
                            if (type === 'detail') {
                                if (!this.detailAlreadyEnteredManually.detailNo.includes(value)) {
                                    rows.setControl(index, this.builddetailItem(associatedDetailsArray[0].accountNumber.value, value, associatedDetailsArray[0].detailName, associatedDetailsArray[0].detailCountry));
                                    this.detailAlreadyEnteredManually.detailNo.push(value);

                                    for (let i = 1; i < associatedDetailsArray.length; i++)
                                        rows.insert(index + i, this.builddetailItem(associatedDetailsArray[i].accountNumber.value, value, associatedDetailsArray[i].detailName, associatedDetailsArray[i].detailCountry));
                                }

                                //if search mode is 'account'
                            } else if (type === 'account') {
                                if (!this.detailAlreadyEnteredManually.accountNumber.includes(value)) {
                                    rows.setControl(index, this.builddetailItem(value, associatedDetailsArray[0].detailNo.value, associatedDetailsArray[0].detailName, associatedDetailsArray[0].detailCountry));
                                    this.detailAlreadyEnteredManually.accountNumber.push(value);

                                    for (let i = 1; i < associatedDetailsArray.length; i++)
                                        rows.insert(index + i, this.builddetailItem(value, associatedDetailsArray[i].detailNo.value, associatedDetailsArray[i].detailName, associatedDetailsArray[i].detailCountry));
                                }
                            }
                        }
                    },
                    error => console.log(error));
        }
    }
}

默认情况下,FormGroup中的最后两个字段为readonly。一旦用户在前两个字段中的任何一个字段中输入内容并聚焦,就应该获取与该值相关联的详细信息,替换当前FormGroup并附加生成列表中的其他FormGroup。我希望新添加的FormControl中的所有FormGroup都应为readonly。用户可以添加更多字段,并重复该过程。

1 个答案:

答案 0 :(得分:2)

根据这个:https://github.com/angular/angular/issues/11447,无法在表单控件上添加readonly,只支持disabled

我甚至更喜欢disabled,因为它在视觉上(灰色)显示用户无法触摸它。因此,当您想要禁用formcontrol时,只需使用:

formControlNameHere.disable();

或者如果您需要禁用整个表单组,可以使用

以相同的方式执行此操作
myFormGroupNameHere.disable()

我们需要记住的是,这个formcontrol然后从表单对象中排除。要获取所有禁用的值,您需要调用:

this.myForm.getRawValue();

如果您确实要添加readonly,则需要为其执行一些解决方法:https://stackoverflow.com/a/45452289/7741865

[readonly]="anyBooleanPropertyFromComponent" 

当然在那个答案中我们使用一个布尔值,这当然不适合你,然后我看到你需要设置一个额外的布尔形式控件,然后你可以用{{1}绑定}。但那只是为你的表单组添加一个新的“不必要”属性,所以另一个原因就是[readonly] :)

希望这有帮助!