TypeError: this.form._updateTreeValidity is not a function

40,936

Solution 1

Binding the template variable #contactForm appears to cause a name conflict and blow up the template processor as it tries to turn the attached template variable into an NgForm on the backend. Everywhere I have seen model driven forms used there is no template variable binding on the form, whereas there is a #tv="ngForm" utilized in template driven forms. It appears there was a miss on the mixing of the two forms approaches which resulted in the error.

Simply removing it will resolve the issue.

Solution 2

When you incorrectly add to your template formGroup="..." instead of [formGroup]="..." you'll also get this error message.

Solution 3

It's been a while, but for me the problem was passing the formGroup to the template instead of referencing it directly.

E.g. this is not working

<ng-template #selectField
             let-field
             let-group
             let-frmName="frmName">
    <ng-container [formGroup]="group">
        <mat-form-field fxFlex="32"
                        floatLabel="always">
            <mat-label>{{field.label}}</mat-label>
            <mat-select [formControlName]="frmName"
                        [required]="field.required">
                <mat-option *ngFor="let option of field.options"
                            [value]="option.value">
                    {{option.description}}
                </mat-option>
            </mat-select>
        </mat-form-field>
    </ng-container>
</ng-template>

If I use directly my formGroup instance it works just fine.

Hope this helps.

Solution 4

I had a dynamic form. I got above error since I didn't init it inside the ngOnInit()

Solution:

checkInForm: FormGroup;

ngOnInit(){
    this.checkInForm = this.formBuilder.group({});
}

Solution 5

This can happen when you're using the input name formControl or formGroup on a custom component which isn't a form control.

Change your custom component to accept a different input name:

Change this

@Input()
formGroup: string
// ^ Causes issues

To this

@Input()
group: string
Share:
40,936
Harish Vangavolu
Author by

Harish Vangavolu

Waddup! I'm a dev!

Updated on July 24, 2022

Comments

  • Harish Vangavolu
    Harish Vangavolu almost 2 years

    I'm currently using Angular Forms version 2.0.0 and trying to make a contact us modal with a contact form inside.

    Immediately after the ContactComponent loads, I get:

    EXCEPTION: this.form._updateTreeValidity is not a function

    Can't fine this.form._updateTreeValidity

    1. I've already seen some other stack posts suggesting that using FormGroup instead of FormBuilder to init the form object in the component constructor is now standard with the new API so I've updated that.

    2. I import ReactiveFormsModule and FormsModule along with all the form related components and the error doesn't seem to be module related.

    3. My TypeScript isn't throwing errors in compile time and Visual Studio Intellisense seems to be able to find all FormGroup functions just fine so why is this happening at runtime?...

    My code:

    contact.component.ts:

    import { Component, Input, ViewChild } from '@angular/core';
    import { ApiService } from '../../../services/api.service';
    import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
    import { Router, ActivatedRoute, Params } from '@angular/router';
    import { FormsModule, ReactiveFormsModule, FormGroup, FormControl, Validators } from '@angular/forms';
    import 'rxjs/Rx';
    
    declare var jQuery: any;
    
    @Component({
        selector: 'my-contact',
        templateUrl: 'app/modules/footer/contact/contact.html'
    })
    export class ContactComponent {
    
        private contactForm: FormGroup;
        private invalidEmail: boolean;
        private invalidSubject: boolean;
        private invalidMessage: boolean;
    
        constructor(private apiService: ApiService, private router: Router, private route: ActivatedRoute) {
            this.contactForm = new FormGroup({
                emailControl: new FormControl('', <any>Validators.required),
                subjectControl: new FormControl('', <any>Validators.required),
                messageControl: new FormControl('', <any>Validators.required)
            });
        }
    
        submit() {
    
            if (this.contactForm.valid) {
                this.apiService.sendMessage(this.contactForm.controls['emailControl'].value, this.contactForm.controls['subjectControl'].value, this.contactForm.controls['messageControl'].value);
            }
    
            if (!this.contactForm.controls['emailControl'].valid) {
                this.invalidEmail = true;
            }
            if (!this.contactForm.controls['subjectControl'].valid) {
                this.invalidSubject = true;
            }
            if (!this.contactForm.controls['messageControl'].valid) {
                this.invalidMessage = true;
            }
    
        }
    
        ngOnInit() {
            this.invalidEmail = false;
            this.invalidSubject = false;
            this.invalidMessage = false;
        }
    
    }
    

    contact.html:

    <modal-header class="c-no-border" [show-close]="true">
      <h4 class="modal-title text-uppercase">Send us a message</h4>
    </modal-header>
    
    <form novalidate #contactForm [formGroup]="contactForm" (ngSubmit)="submit()">
      <div class="modal-body">
        <div class="form-group">
          <label for="email" class="control-label">Email</label>
          <input name="email" formControlName="emailControl" placeholder="" type="text" class="c-square form-control c-margin-b-20" id="email">
          <div class="c-font-red-1" *ngIf="invalidEmail" style="position: absolute;">*Required</div>
          <label for="subject" class="control-label">Subject</label>
          <input name="subject" formControlName="subjectControl" placeholder="" type="text" class="c-square form-control c-margin-b-20" id="subject">
          <div class="c-font-red-1" *ngIf="invalidSubject" style="position: absolute;">*Required</div>
          <textarea formControlName="messageControl" style="resize: vertical;" class="c-square form-control c-margin-b-20" id="content" (keyup.enter)="submit()"></textarea>
          <div class="c-font-red-1" *ngIf="invalidMessage" style="position: absolute;">*Required</div>
        </div>
      </div>
      <modal-footer class="c-no-padding">
        <button type="button" class="btn c-btn-square c-btn-bold c-btn-uppercase pull-right">Cancel</button>
        <button type="submit" class="btn c-theme-btn c-btn-square c-btn-bold c-btn-uppercase pull-right" style="margin-right: 10px;">Send</button>
      </modal-footer>
    </form>
    

    app.module.ts:

    import { NgModule, enableProdMode }      from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { AppComponent } from './app.component';
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';
    import { QueuesModule }     from './modules/queues/queues.module';
    import { OrderModule }     from './modules/order/order.module';
    import { AccountModule } from './modules/account/account.module';
    import { AdminModule } from './modules/admin/admin.module';
    import { routing } from './app.routing';
    import { GridModule } from '@progress/kendo-angular-grid';
    import { SplashComponent } from './modules/splash/splash.component';
    import { ContactComponent } from './modules/footer/contact/contact.component';
    
    import { SharedModule } from './shared/shared.module';
    import { EmailValidator } from './shared/utilities/custom-validators'
    
    import { CookieService } from 'angular2-cookie/services/cookies.service';
    import { HttpModule, Response } from '@angular/http';
    import { StringService } from './services/string.service';
    import { ApiService } from './services/api.service';
    import { UserService } from './services/user.service';
    import { OrderService } from './services/order.service';
    import { OrderGuard } from './services/order-guard.service';
    import { FooterComponent } from './modules/footer/footer.component';
    import { ErrorComponent } from './modules/error/error.component';
    import { CustomFormsModule } from "ng2-validation";
    
    @NgModule({
        imports: [
            BrowserModule,
            FormsModule,
            ReactiveFormsModule,
            HttpModule,
            QueuesModule,
            OrderModule,
            AccountModule,
            AdminModule,
            routing,
            GridModule,
            SharedModule,
            Ng2Bs3ModalModule,
            CustomFormsModule
        ],
        declarations: [
            AppComponent,
            SplashComponent,
            FooterComponent,
            ErrorComponent,
            ContactComponent
        ],
        providers: [
            StringService,
            ApiService,
            UserService,
            CookieService,
            OrderService,
            OrderGuard
        ],
        bootstrap: [AppComponent],
        exports: [
        ]
    })
    
    export class AppModule {
    }