开发者问题收集

TypeError:无法读取 null 的属性“无效”-Angular Reactive Forms

2019-07-17
7607

我的 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

export class SettingsComponent implements 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>
3个回答

用户表单数组名称

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

只需将

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

更改为

<mat-error *ngIf="en​​dingRange && endingRange.invalid"> <p>IP 地址无效。</p> </mat-error>

Baruch Gans
2019-07-17

endingRange 在 ipRangeForm 中不存在,它存在于 ipRanges 成员中。

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

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

Qellson
2019-07-17