0

I'm trying to use angular material 2 datepicker with angular forms and I'm getting this error:

vendor.bundle.js:92803 ERROR TypeError: Cannot read property 'invalid' of undefined
    at MdInput.defaultErrorStateMatcher [as errorStateMatcher] (vendor.bundle.js:121344)
    at MdInput.webpackJsonp.../../../material/@angular/material.es5.js.MdInput._updateErrorState (vendor.bundle.js:131778)
    at MdInput.webpackJsonp.../../../material/@angular/material.es5.js.MdInput.ngDoCheck (vendor.bundle.js:131739)
    at checkAndUpdateDirectiveInline (vendor.bundle.js:102634)
    at checkAndUpdateNodeInline (vendor.bundle.js:104132)
    at checkAndUpdateNode (vendor.bundle.js:104071)
    at prodCheckAndUpdateNode (vendor.bundle.js:104765)
    at Object.View_FormComponent_0._co [as updateDirectives] (ng:///AppModule/FormComponent.ngfactory.js:2337)
    at Object.updateDirectives (vendor.bundle.js:104522)
    at checkAndUpdateView (vendor.bundle.js:104038)

Below is the code form my comonent :

import {Component, OnInit, Output, Input, EventEmitter} from "@angular/core";
import {FormControl, Validators, FormGroup} from "@angular/forms";
import {ReferentialService} from "../shared/referential.service";

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.css']
})
export class FormComponent implements OnInit {

  private form: FormGroup;
  @Input() model: any;
  isValidationMode: boolean;

  @Output('cancel') cancel$: EventEmitter<any>;
  @Output('submit') submit$: EventEmitter<any>;


  // select lists
  languages: any;
  types: any;
  subtypes: any;
  entities: any;
  managements: any;
  countries: any;
  services: any;

  constructor(private _referentialService: ReferentialService) {
    this.submit$ = new EventEmitter();
    this.cancel$ = new EventEmitter();
    this.model = {};
    this.form = this._buildForm();
  }

  ngOnInit() {
    this.initSelectLists();
  }

  /**
   * Function to handle component update
   *
   * @param record
   */
  ngOnChanges(record) {
    if (record.model && record.model.currentValue) {
      this.model = record.model.currentValue;
      this.isValidationMode = !!this.model;
      this.form.patchValue(this.model);
    }
  }

  /**
   * Function to init select list
   */
  initSelectLists() {
    this._referentialService.getCountries().subscribe((countries: any[]) => this.countries = countries);
    this._referentialService.getLanguages().subscribe((languages: any[]) => this.languages = languages);
    this._referentialService.getTypes().subscribe((types: any[]) => this.types = types);
    this._referentialService.getSubTypes().subscribe((subtypes: any[]) => this.subtypes = subtypes);
    this._referentialService.getEntities().subscribe((entities: any[]) => this.entities = entities);
    this._referentialService.getServices().subscribe((services: any[]) => this.services = services);
    this._referentialService.getManagements().subscribe((managements: any[]) => this.managements = managements);
  }

  /**
   * Function to emit event to cancel process
   */
  cancel() {
    this.cancel$.emit();
  }

  /**
   * Function to emit event to submit form and person
   */
  submit(doc: any) {
    this.submit$.emit(doc);
  }

  /**
   * Function to build our form
   *
   * @returns {FormGroup}
   *
   * @private
   */
  private _buildForm(): FormGroup {
    return new FormGroup({
      file: new FormControl('', Validators.compose([])),
      documentid: new FormControl('', Validators.compose([Validators.required])),
      title: new FormControl('', Validators.compose([Validators.required])),
      name: new FormControl('', Validators.compose([Validators.required])),
      format: new FormControl('', Validators.compose([Validators.required])),
      summary: new FormControl('', Validators.compose([Validators.required])),
      mnesysid: new FormControl('', Validators.compose([Validators.required])),
      entity: new FormControl('', Validators.compose([Validators.required])),
      management: new FormControl('', Validators.compose([])),
      service: new FormControl('', Validators.compose([])),
      creationDate: new FormControl(null, Validators.compose([])),
      sendDate: new FormControl({
        value: this.model.creationDate
      }, Validators.compose([Validators.required])),
      type: new FormControl('', Validators.compose([Validators.required])),
      subtype: new FormControl('', Validators.compose([])),
      archivist: new FormControl({
        value: this.model.archivist,
        disabled: true
      }, Validators.compose([Validators.required])),
      firstname: new FormControl({value: this.model.name, disabled: true}, Validators.compose([Validators.required])),
      lastname: new FormControl({
        value: this.model.firstname,
        disabled: true
      }, Validators.compose([Validators.required])),
      beneficiary: new FormControl('', Validators.compose([])),
      depositid: new FormControl('', Validators.compose([])),
      filepath: new FormControl('', Validators.compose([])),
      isprivate: new FormControl('', Validators.compose([])),
      language: new FormControl('', Validators.compose([Validators.required])),
      country: new FormControl('', Validators.compose([])),
      publicyear: new FormControl(null, Validators.compose([])),
      version: new FormControl('', Validators.compose([])),
      status: new FormControl('', Validators.compose([])),
      comment: new FormControl('', Validators.compose([Validators.required]))
    });
  }
}

And this is my html code

<md-card>

  <md-card-title>
    <span *ngIf="isValidationMode" style="color:  #00965E !important;">Validation du document</span>
    <span *ngIf="!isValidationMode" style="color:  #00965E !important;">Soumission de document</span>
  </md-card-title>

  <md-card-content>
    <form novalidate [formGroup]="form">
      <h5 style="margin-bottom: -5px">Personne déposant le fichier</h5>
      <table>
        <tr>
          <td>
            <p [class.errors]="form.controls.archivist.touched && form.controls.archivist.invalid">
              <md-input-container>
                <input mdInput placeholder="Identifiant" formControlName="archivist">
                <span *ngIf="form.controls.archivist.touched && form.controls.archivist.errors?.required">
              <br>L'identifiant de l'archivist est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <p [class.errors]="form.controls.lastname.touched && form.controls.lastname.invalid">
              <md-input-container>
                <input mdInput placeholder="Nom" formControlName="lastname">
                <span *ngIf="form.controls.lastname.touched && form.controls.lastname.errors?.required">
              <br>le nom est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <p [class.errors]="form.controls.firstname.touched && form.controls.firstname.invalid">
              <md-input-container>
                <input mdInput placeholder="Prenom" formControlName="firstname">
                <span *ngIf="form.controls.firstname.touched && form.controls.firstname.errors?.required">
              <br>le prénom est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <md-input-container>
              <input mdInput formControlName="beneficiary" placeholder="Pour le compte de">
            </md-input-container>
          </td>
        </tr>
      </table>
      <h5 class="sub-title">Identification du document</h5>
      <table>
      </table>
      <table>
        <tr>
          <td>
            <input type="file" (change)="fileChange($event)" formControlName="file" placeholder="Upload file"
                   accept=".pdf,.doc,.docx">
          </td>
          <td>
            <p [class.errors]="form.controls.title.touched && form.controls.title.invalid">
              <md-input-container>
                <input mdInput placeholder="Titre" formControlName="title">
                <span *ngIf="form.controls.title.touched && form.controls.title.errors?.required">
              <br>le titre est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <p [class.errors]="form.controls.format.touched && form.controls.format.invalid">
              <md-input-container>
                <input mdInput placeholder="Format" formControlName="format">
                <span *ngIf="form.controls.format.touched && form.controls.format.errors?.required">
              <br>le format est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <p [class.errors]="form.controls.documentid.touched && form.controls.documentid.invalid">
              <md-input-container>
                <input mdInput placeholder="Identifiant" formControlName="documentid">
                <span *ngIf="form.controls.documentid.touched && form.controls.documentid.errors?.required">
              <br>l'identifiant est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <p [class.errors]="form.controls.mnesysid.touched && form.controls.mnesysid.invalid">
              <md-input-container>
                <input mdInput placeholder="Cote" formControlName="mnesysid">
                <span *ngIf="form.controls.mnesysid.touched && form.controls.mnesysid.errors?.required">
                <br>la cote est obligatoire</span>
              </md-input-container>
            </p>
          </td>
        </tr>
      </table>
      <h5 class="sub-title">Description du document</h5>
      <table>
        <tr>
          <td>
            <p [class.errors]="form.controls.name.touched && form.controls.name.invalid">
              <md-input-container>
                <input mdInput placeholder="Nom" formControlName="name">
                <span *ngIf="form.controls.name.touched && form.controls.name.errors?.required">
              <br>Le nom est obligatoire</span>
              </md-input-container>
            </p>
          </td>
          <td>
            <md-input-container><input mdInput placeholder="Version" formControlName="version"></md-input-container>
          </td>
          <td>
            <p [class.errors]="form.controls.language.touched && form.controls.language.invalid">
              <md-select placeholder="Langue" formControlName="language">
                <md-option>None</md-option>
                <md-option *ngFor="let language of languages" [value]="language.languageCode">{{ language.frenchLabel
                  }}
                </md-option>
              </md-select>
              <span *ngIf="form.controls.language.touched && form.controls.language.errors?.required">
              <br><br>La langue est obligatoire</span>
            </p>
          </td>
          <td>
            <md-select placeholder="Pays" formControlName="country">
              <md-option>None</md-option>
              <md-option *ngFor="let country of countries" [value]="country.countryCode">{{ country.frenchLabel }}
              </md-option>
            </md-select>
          </td>
        </tr>
      </table>
      <table>
        <tr>
          <td>
            <p [class.errors]="form.controls.summary.touched && form.controls.summary.invalid">
              <md-input-container>
                <textarea mdInput placeholder="Résumé" formControlName="summary"
                          class="text-area"></textarea>
                <span *ngIf="form.controls.summary.touched && form.controls.summary.errors?.required">
              <br>Le résumé est obligatoire</span>
              </md-input-container>
            </p>
          </td>
        </tr>
      </table>
      <table>
        <tr>
          <td>
            <p [class.errors]="form.controls.type.touched && form.controls.type.invalid">
              <md-select placeholder="Type" formControlName="type">
                <md-option>None</md-option>
                <md-option *ngFor="let type of types" [value]="type.typeCode">{{ type.frenchLabel }}</md-option>
              </md-select>
              <span *ngIf="form.controls.type.touched && form.controls.type.errors?.required">
              <br><br>Le type est obligatoire</span>
            </p>
          </td>
          <td>
            <md-select placeholder="Sous type" formControlName="subtype">
              <md-option>None</md-option>
              <md-option *ngFor="let subtype of subtypes" [value]="subtype.subtypeCode">{{ subtype.frenchLabel }}
              </md-option>
            </md-select>
          </td>
          <td>
            <p [class.errors]="form.controls.entity.touched && form.controls.entity.invalid">
              <md-select placeholder="Entité" formControlName="entity">
                <md-option>None</md-option>
                <md-option *ngFor="let entity of entities" [value]="entity.entityCode">{{ entity.frenchLabel }}
                </md-option>
              </md-select>
              <span *ngIf="form.controls.entity.touched && form.controls.entity.errors?.required">
              <br><br>L'entité est obligatoire</span>
            </p>
          </td>
          <td>
            <md-select placeholder="Direction" formControlName="management">
              <md-option>None</md-option>
              <md-option *ngFor="let management of managements" [value]="management.managementCode">{{
                management.frenchLabel }}
              </md-option>
            </md-select>
          </td>
          <td>
            <md-select placeholder="Métier/Service" formControlName="service">
              <md-option>None</md-option>
              <md-option *ngFor="let service of services" [value]="service.serviceCode">{{ service.frenchLabel }}
              </md-option>
            </md-select>
          </td>
        </tr>
      </table>
      <h5 style="margin-top: 5px;margin-bottom: -5px">Création du document</h5>
      <table>
        <tr>
          <td style="padding-right: 40px;">
            <md-radio-group formControlName="isprivate" required>
              <md-radio-button value="false" color="primary">Public</md-radio-button>
              <md-radio-button value="true" color="primary" [checked]="isprivate">Privé</md-radio-button>
            </md-radio-group>
          </td>
          <td>
            <md-form-field>
              <input mdInput [mdDatepicker]="creationDatePicker" placeholder="Date de création"
                     formControlName="creationDate">
              <md-datepicker-toggle mdSuffix [for]="creationDatePicker"></md-datepicker-toggle>
              <md-datepicker #creationDatePicker></md-datepicker>
            </md-form-field>
          </td>
          <!--<td>-->
            <!--<md-form-field>-->
              <!--<input mdInput [mdDatepicker]="sendDatePicker" placeholder="Date d'envoi" formControlName="sendDate">-->
              <!--<md-datepicker-toggle mdSuffix [for]="sendDatePicker"></md-datepicker-toggle>-->
              <!--<md-datepicker #sendDatePicker></md-datepicker>-->
            <!--</md-form-field>-->
          <!--</td>-->
          <!--<td>-->
            <!--<md-form-field>-->
              <!--<input mdInput [mdDatepicker]="publicationDatePicker" placeholder="Date de passage en public"-->
                     <!--formControlName="publicyear">-->
              <!--<md-datepicker-toggle mdSuffix [for]="publicationDatePicker"></md-datepicker-toggle>-->
              <!--<md-datepicker #publicationDatePicker></md-datepicker>-->
            <!--</md-form-field>-->
          <!--</td>-->
        </tr>
      </table>
      <table>
        <tr>
          <td>
            <p *ngIf="isValidationMode" [class.errors]="form.controls.comment.touched && form.controls.comment.invalid">
              <md-input-container>
                <textarea mdInput placeholder="Commentaire" formControlName="comment"
                          class="text-area"></textarea>
                <span *ngIf="form.controls.summary.touched && form.controls.comment.errors?.required">
              <br>Le commentaire est obligatoire</span>
              </md-input-container>
            </p>
          </td>
        </tr>
      </table>
    </form>
  </md-card-content>

  <md-card-actions align="end">
    <div *ngIf="isValidationMode">
      <button md-button align [hidden]="!isValidationMode">Refuser</button>
    </div>
    <div>
      <button md-button type="button" (click)="cancel()">Annuler</button>
    </div>
    <div>
      <button md-button color="primary" type="submit" (click)="submit(form.value)" >
        <span *ngIf="!isValidationMode">Soumettre</span>
        <span *ngIf="isValidationMode">Valider</span>
      </button>
    </div>
  </md-card-actions>

</md-card>

The date that i'm trying to bind from my model has this format "2017-06-20T12:00:00.000Z"

Could you please help me ? is there a need to put on place a dateAdapter ?

3
  • I'm not sure If it's related to the datepicker. The error say Cannot read property 'invalid' of undefined. This means that any object of form.controls.*.invalid can be undefined. And you are already posting the error of your build version, if possible try to debug in dev and find which object give the error. Commented Sep 1, 2017 at 9:33
  • Hello, thanks for your answer. Yes, I verified thar the error is cause by the creation date object. Commented Sep 1, 2017 at 10:04
  • Then focus on that. Commented Sep 1, 2017 at 10:07

1 Answer 1

6

Your error:

TypeError: Cannot read property 'invalid' of undefined

is actually caused by this exception:

Datepicker: value not recognized as a date object by DateAdapter.

This means that the date format "2017-06-20T12:00:00.000Z" you're using in your model is not a valid Date instance. See this line in the source code.

So you should use a Date instance like so:

return new FormGroup({
  creationDate: new FormControl(new Date(2017, 6, 20)),
})

or in your model:

model.creationDate = new Date(2017, 6, 20);

Also, as mentioned in the documentations:

Please note: MdNativeDateModule is based off of the functionality available in JavaScript's native Date object, and is thus not suitable for many locales. One of the biggest shortcomings of the native Date object is the inability to set the parse format. We highly recommend using a custom DateAdapter that works with the formatting/parsing library of your choice.

You should not rely on the NativeDateAdapter since it's using the native JavaScript Date object, which is very limited when it comes to parsing complexe date formats. For that, you could for instance use the awesome Moment.js library.

Sign up to request clarification or add additional context in comments.

4 Comments

doing creationDate: new Date(); saved me! Thanks :)
Is there a moment Angular wrapper?
yes, there is this module by my friend Uri: github.com/urish/angular2-moment
Initiating the model.creationdate with new Date() has resolved the problem. Many thanks for your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.