TypeError:无法读取null的属性“无效”-Angular反应式窗体

时间:2019-07-17 12:18:27

标签: angular angular-reactive-forms

我在Angular应用程序中有一个反应形式,该形式用于接收用户的IP地址范围。我正在使用反应形式,以便用户可以随意输入和删除IP范围。

窗体本身利用FormBuilder创建具有两个窗体控件的FormArray,这些控件是文本输入。创建表单的所有代码和每个表单数组元素都相对简化。但是,似乎与在表单中显示验证错误有关。具体来说,

<mat-error *ngIf="endingRange.invalid">
    <p>IP address is not valid.</p>
</mat-error>

如果我注释掉这些行,则表单可以正常工作而不会出现任何问题。但是,如果我没有注释行,则开始出现以下错误:

TypeError: Cannot read property 'invalid' of null

这对我来说并没有多大意义,因为我可以在这样的组件文件中声明此特定的表单控件

get endingRange() {
        return this.ipRangeForm.get('endingRange');
    }

另一个可能是问题的方面是,表单最初是从视图中隐藏的,并且可以通过使用切换开关来启用。我不确定是否会导致错误,但值得一提。您可以在以下文件中查看其逻辑。

这是正在使用的完整文件。

SettingsComponent

导出类SettingsComponent实现OnInit {

ipRestrictionEnabled: boolean;
ipRangeForm: FormGroup;

constructor(
    baseService: PageService, private formBuilder: FormBuilder
) {
    super(baseService);
}

ngOnInit() {
    this.ipRestrictionEnabled = false;
    this.ipRangeForm = this.formBuilder.group(
        {
            ipRanges: this.formBuilder.array([])
        }
    );
}

ngOnDestroy() {
    this.destroy$.next(true);
}

getPageConfig() {
    return {
        pageKey: 'settings',
        displaySidebar: true,
        displayToolbar: true,
        backButtonRoute: ''
    };
}

toggleIpRestriction(): void {
    this.ipRestrictionEnabled = !this.ipRestrictionEnabled;
}

get ipRangeForms() {
    return this.ipRangeForm.get('ipRanges') as FormArray;
}

addRange() {
    const ipRange = this.formBuilder.group({
        startingRange: ['',
            [
                Validators.required,
                // tslint:disable-next-line:max-line-length
                Validators.pattern('^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$')
            ]
        ],
        endingRange: ['',
            [
                Validators.required,
                // tslint:disable-next-line:max-line-length
                Validators.pattern('^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$')
            ]
        ]
    });

    this.ipRangeForms.push(ipRange);
}

get startingRange() {
    return this.ipRangeForm.get('ipRanges').get('startingRange');
}

get endingRange() {
    return this.ipRangeForm.get('ipRanges').get('endingRange');
}

deleteRange(index) {
    this.ipRangeForms.removeAt(index);
}

submitIpRanges() {
    console.log(this.ipRangeForms.getRawValue());
}

}

SettingsComponent

<ng-container *ngIf="ipRestrictionEnabled">
        <div class="row mt-xl">
            <div class="col-12">
                <h4>{{ getTranslateKey('ipRanges') | translate }}</h4>
                <p>{{ getTranslateKey('ipRangesDescription') | translate }}</p>
            </div>
        </div>

        <div class="row">
            <div class="col-12">
                <form [formGroup]="ipRangeForm">
                    <div formArrayName="ipRanges">
                        <div *ngFor="let ranges of ipRangeForms.controls; let i=index" [formGroupName]="i">

                            <div class="row mb-lg">
                                <div class="col-6">
                                    <mat-card>
                                        <div class="row">
                                            <div class="col-5">

                                                <mat-form-field style="width: 100%;">
                                                    <label>
                                                        <input matInput placeholder="{{ getTranslateKey('startingRange.label') | translate }}" value="" formControlName="startingRange">
                                                    </label>
                                                    <mat-error *ngIf="startingRange.invalid">
                                                        <p>IP address is not valid.</p>
                                                    </mat-error>
                                                </mat-form-field>

                                            </div>
                                            <div class="col-5">

                                                <mat-form-field style="width: 100%;">
                                                    <label>
                                                        <input matInput placeholder="{{ getTranslateKey('endingRange.label') | translate }}" value="" formControlName="endingRange">
                                                    </label>
<!--                                                    <mat-error *ngIf="endingRange.invalid">-->
<!--                                                        <p>IP address is not valid.</p>-->
<!--                                                    </mat-error>-->
                                                </mat-form-field>

                                            </div>
                                            <div class="col-2 remove-column">
                                                <button swui-core-button (click)="deleteRange(i)" class="mr-sm pd-zero"
                                                        color="secondary" buttonStyle="link">
                                                    {{ getTranslateKey('remove') | translate }}
                                                </button>
                                            </div>
                                        </div>
                                    </mat-card>
                                </div>
                            </div>


                        </div>
                    </div>
                </form>
            </div>
        </div>

        <div class="row">
            <div class="col-12">
                <button swui-core-button (click)="addRange()" class="mr-sm" color="secondary" buttonStyle="link">
                    <mat-icon class="button-icon">add</mat-icon>
                    {{ getTranslateKey('addIP') | translate }}
                </button>
            </div>
        </div>
    </ng-container>

5 个答案:

答案 0 :(得分:2)

用户表单数组名称

lbl_geheel.Text += node.InnerText;

答案 1 :(得分:0)

只是改变

<mat-error *ngIf="endingRange.invalid">
    <p>IP address is not valid.</p>
</mat-error>

<mat-error *ngIf="endingRange && endingRange.invalid"> <p>IP address is not valid.</p> </mat-error>

答案 2 :(得分:0)

结尾范围在ipRangeForm上不存在,它存在于ipRanges成员上。

this.ipRangeForm = this.formBuilder.group(
    {
        ipRanges: this.formBuilder.array([])
    }
);

您需要将验证附加到每个formArray成员

答案 3 :(得分:0)

我认为在第一次get调用和formGroup初始化之间存在很小的延迟。 忽略那个;只需问问问号endingRange

<mat-error *ngIf="endingRange?.invalid">
    <p>IP address is not valid.</p>
</mat-error>

因此,这将在检查endingRange属性之前对invalid进行角度检查。

答案 4 :(得分:0)

问题是您正在访问ipRanges,就好像它不是数组一样。 Angular无法知道您想要终止范围的数组中的哪个IP范围。尝试以下方法:

getEndingRange(idx:number) {
  return this.ipRangeForms.controls[idx].get(‘endingRange’);
}

然后在模板中,将索引输入到函数中。

<mat-error *ngIf="getEndingRange(i).invalid">

对开始范围进行相同操作