简体   繁体   中英

Angular Update form populates input fields but still returns error in console?

I am trying to create an update form in Angular. I have tried many things but then again im not very familiar with Angular to begin with. This seems pretty straight forward though, I am getting the data using the ngOnInit() method (which is returning the correct data). The user data is displayed in the input fields but then the error comes up.

This is the error that I get in the console:

UpdateComponent.html:6 ERROR TypeError: Cannot read property 'firstName' of undefined
    at Object.eval [as updateDirectives] (UpdateComponent.html:6)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:11914)
    at checkAndUpdateView (core.js:11307)
    at callViewAction (core.js:11548)
    at execComponentViewsAction (core.js:11490)
    at checkAndUpdateView (core.js:11313)
    at callViewAction (core.js:11548)
    at execEmbeddedViewsAction (core.js:11511)
    at checkAndUpdateView (core.js:11308)
    at callViewAction (core.js:11548)

My update.component.html file:

<div>
<h2 class="page-header">Edit your Profile</h2>
<form (ngSubmit)="onUpdateSubmit(user)" novalidate>
  <div class="form-group">
    <label for="firstName">First Name</label>
    <input type="text" [(ngModel)]="user.firstName" name="firstName" class="form-control" id="firstName" placeholder="First Name">
  </div>
  <div class="form-group">
    <label for="lastName">Last Name</label>
    <input type="text" [(ngModel)]="user.lastName" name="lastName" class="form-control" id="lastName" placeholder="Last Name">
  </div>
  <div class="form-group">
    <label for="age">Age</label>
    <input type="number" [(ngModel)]="user.age" name="age" class="form-control" id="age" placeholder="Age" min="0" max="200">
  </div>
  <div class="form-group">
    <label for="favoriteFood">What is your Favorite Food?</label>
    <input type="text" [(ngModel)]="user.favoriteFood" name="favoriteFood" class="form-control" id="favoriteFood" placeholder="Favorite Food">
  </div>
  <div class="form-group">
    <label for="username">Username</label>
    <input type="text" [(ngModel)]="user.username" name="username" class="form-control" id="username" placeholder="Username">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail1">Email address</label>
    <input type="email" [(ngModel)]="user.email" name="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
    <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
  </div>
  <div class="form-group">
    <label for="exampleInputPassword1">Password</label>
    <input type="password" [(ngModel)]="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>
</div><div>
<h2 class="page-header">Edit your Profile</h2>
<form (ngSubmit)="onUpdateSubmit(user)" novalidate>
  <div class="form-group">
    <label for="firstName">First Name</label>
    <input type="text" [(ngModel)]="user.firstName" name="firstName" class="form-control" id="firstName" placeholder="First Name">
  </div>
  <div class="form-group">
    <label for="lastName">Last Name</label>
    <input type="text" [(ngModel)]="user.lastName" name="lastName" class="form-control" id="lastName" placeholder="Last Name">
  </div>
  <div class="form-group">
    <label for="age">Age</label>
    <input type="number" [(ngModel)]="user.age" name="age" class="form-control" id="age" placeholder="Age" min="0" max="200">
  </div>
  <div class="form-group">
    <label for="favoriteFood">What is your Favorite Food?</label>
    <input type="text" [(ngModel)]="user.favoriteFood" name="favoriteFood" class="form-control" id="favoriteFood" placeholder="Favorite Food">
  </div>
  <div class="form-group">
    <label for="username">Username</label>
    <input type="text" [(ngModel)]="user.username" name="username" class="form-control" id="username" placeholder="Username">
  </div>
  <div class="form-group">
    <label for="exampleInputEmail1">Email address</label>
    <input type="email" [(ngModel)]="user.email" name="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
    <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
  </div>
  <div class="form-group">
    <label for="exampleInputPassword1">Password</label>
    <input type="password" [(ngModel)]="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>

My update.component.ts file:

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { ValidateService } from '../../services/validate.service';
import { Router } from "@angular/router";
import { FlashMessagesService } from 'angular2-flash-messages';

@Component({
  selector: 'app-update',
  templateUrl: './update.component.html',
  styleUrls: ['./update.component.css']
})
export class UpdateComponent implements OnInit {
  user: Object;

  constructor(
    private authService: AuthService,
    private validateService: ValidateService,
    private router: Router,
    private _flashMessagesService: FlashMessagesService
  ) { }

  ngOnInit() {
    this.authService.getProfile().subscribe(profile => {
      this.user = profile.user;
    },
    err => {
      console.log(err);
      return false;
    });
  }

  onUpdateSubmit(user) {
    console.log("Component", user)
    // Required Fields
    if(!this.validateService.validateSignup(user)) {
      this._flashMessagesService.show("Please fill in all fields", {cssClass: "alert-danger", timeout: 3000});
      return false;
    }

    // Validate Email
    if(!this.validateService.validateEmail(user.email)) {
      this._flashMessagesService.show("Please use valid email", {cssClass: "alert-danger", timeout: 3000});
      return false;
    }

    // Update user
    this.authService.updateUser(user).subscribe(data => {
      if(data.success) {
        this._flashMessagesService.show("Update Success!", {cssClass: "alert-success", timeout: 3000});
        this.router.navigate(["/profile"]);
      } else {
        this._flashMessagesService.show("Something went wrong", {cssClass: "alert-danger", timeout: 3000});
        this.router.navigate(["/update"]);
      }
    });
  }

}

This is because there is no firstName returned in user data. Maybe it is undefined. To avoid the issue.

You'd better: 1. Check the user data in ngOnInit() if it is returned. 2. Initial user data. e,g: user = { firstName: '' }; 3. Check whether there is a delay when get user data from service

You are having a two way binding in your form , then why you need to pass the user on form submit. Try using as below

   <form (ngSubmit)="onUpdateSubmit()" novalidate>
    .
    .
    .

and use

  onUpdateSubmit() {
    console.log("Component", this.user);
    .
    .
    .
 }

Your error message is clear. Your user is populated by api call on ngOnInit which however, may return a response after the html is loaded. While loading, your DOM expect user to the available but its undefined in your case. There are few ways you can fix this. First , folloow the usual standard, define your user like below in your constructor.

constructor(
    private authService: AuthService,
    private validateService: ValidateService,
    private router: Router,
    private _flashMessagesService: FlashMessagesService
  ) { 

   this.user = <Object>{};
}

Now your user is not undefined and even though user.name might be , it will be briefly and error will not be thrown. Second option is, update your update.component.html , load your DOM only when user is available or not undefined. To do this, add *ngIf in your first div

<div *ngIf="user">
<h2 class="page-header">Edit your Profile</h2>
<form (ngSubmit)="onUpdateSubmit(user)" novalidate>
........
.........
</form
</div>

Form the above, your form will not be loaded when user is undefined hence the need for user.name is avoided .

This is because there is no firstName defined in user data. This is because at the time of your page loads, your user object is not initialised. If there is no object assigned to this.user in ngOnInit it will return an exception. You can fix this in two ways. One method is to initialize the this.user object at the beginning. It will return a blank form if there is no object is assigned to the user object in ngOnInit but it won't return an exception. You can do it by simply initializing the user object when defining the object or in the constructor.

when defining the object

user={}

or in constructor

this.user={}

Second method is, in case you want to display the form only if there are data you can use the *ngIf to display the form only when the there are data in the user object.

<div *ngIf="user">
<h2 class="page-header">Edit your Profile</h2>
<form (ngSubmit)="onUpdateSubmit(user)" novalidate>
........
.........
</form
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM