0

I'm learning Angular2+ and doing my assignment now. I spent approximately 3 hours trying to debug this bug. I have a problem with my ngFor statement especially with the [value] part. Something is wrong with my code.

The error is :

EmployeeComponent.html:27 ERROR TypeError: Cannot read property 'PositionName' of undefined at Object.eval [as updateDirectives] (EmployeeComponent.html:27) at Object.debugUpdateDirectives [as updateDirectives] (core.js:14689) at checkAndUpdateView (core.js:13836) at callViewAction (core.js:14187) at execEmbeddedViewsAction (core.js:14145) at checkAndUpdateView (core.js:13837) at callViewAction (core.js:14187) at execEmbeddedViewsAction (core.js:14145) at checkAndUpdateView (core.js:13837) at callViewAction (core.js:14187)

So, here's my component html file with the problem spot.

<div class="panel-body" *ngIf="employee">
        <form (ngSubmit)="onSubmit()">
        ......
                    <div class="col-md-6">
                      <div class="form-group"   >
                        <label for="PositionName">Position:</label>
                        <select *ngIf="positions" class="form-control" id="PositionName" name="PositionName" [(ngModel)]="employee.Position.PositionName" >
                          <option *ngFor="let u of positions" [value]="u.PositionName" >{{u.PositionName}}</option>
                        </select>
                      </div>
                    </div>

        .....

        <input type="submit" class="btn btn-primary pull-right" value="Update Employee" />
        </form>
        </div>

I have no idea why it's not letting me to update my API. If I remove this Position field everything works fine e.g. I can update first name, last name etc.

What I've tried

1) *Posting ngIf in several spots

2) Using elvis operator

3) Rewriting code several times

I'm seriously stuck, please help!

here's some files that I'm using.

employee.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Observable";
import { Employee } from "./data/employee";
import { EmployeeRaw } from "./data/employeeRaw";
@Injectable()
export class EmployeeService {

  private url = "https://eanton-teams-api-web422.herokuapp.com";

  constructor(private http:HttpClient) { }

  getEmployees() : Observable<Employee[]> {
    return this.http.get<Employee[]>(`${this.url}/employees`);
  }

  getEmployee(id) : Observable<EmployeeRaw[]> {
    return this.http.get<EmployeeRaw[]>(`${this.url}/employee/` + id);
  }

  saveEmployee(EmployeeRaw) : Observable<any>{
    return this.http.put<any>(this.url + '/employee/' + EmployeeRaw._id, EmployeeRaw);
  }

}

employee.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { EmployeeRaw } from './data/employeeRaw' ;
import { Position } from './data/position' ;

import { EmployeeService } from './employee.service' ;
import { PositionService } from './position.service' ;
import { LogService } from './log.service' ;

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

  employee: EmployeeRaw;
  positions: Position[];

  constructor( private route: ActivatedRoute,
    private e : EmployeeService,
    private p : PositionService) { }

  ngOnInit() {

    const id = this.route.snapshot.paramMap.get('id');


    this.e.getEmployee(id).subscribe( employee => {
      this.employee = employee[0];
      console.log(this.employee);
      //this.hireDate = employee[0].HireDate.format('LL');
    });
    //{{employee.HireDate | amDateFormat:'LL'}}

    this.p.getPositions().subscribe( positions => {
      this.positions = positions;
      console.log(this.positions);
    });

    //DEBUG

    console.log(this.route);
    console.log(id);

    //console.log(now);

    //console.log( this.route.params.id.toString());
  } //ngOnInit

  onSubmit(){
    this.e.saveEmployee(this.employee)
    .subscribe( employee => this.employee = employee );
    console.log(this.employee);

  }

}

data/employeeRaw.ts

export class EmployeeRaw {
            _id: string;
      FirstName: string;
       LastName: string;
  AddressStreet: string;
   AddressState: string;
    AddressCity: string;
     AddressZip: string;
       PhoneNum: string;
      Extension: number;
       Position: string;
       HireDate: string;
    SalaryBonus: number;
            __v: number;
}

data/position.ts

export class Position {
                  _id: string;
         PositionName: string;
  PositionDescription: string;
   PositionBaseSalary: number;
                  __v: number;
}
  • Didn't paste it it was at the top. Corrected the code. I'm actually using *ngIf="employee" before using it. –  Dec 24 '17 at 12:18
  • 1
    `employee.Position.PositionName`: the fiel Position is of type string. strings don't have a PositionName attribute. And the Position is undefined anyway, apparently. – JB Nizet Dec 24 '17 at 12:24
  • You had defined employee.Position as string in your EmployerRaw ! – Eliseo Dec 24 '17 at 12:28
  • Okay guys, I changed Position: string; to Position: Position; however, I still get the same error. I don't know how to fix it. –  Dec 24 '17 at 13:43
  • 1
    Are you sure that the problem is with `*ngFor`? You said that you tried the elvis operator; did you try `employee.Position?.PositionName`? – ConnorsFan Dec 24 '17 at 14:47
  • It doesn't help to have `*ngIf="positions"` if `employee.Position` is `undefined` ;) – AT82 Dec 24 '17 at 19:02
  • employee.Position?.PositionName - throws an error when I try use it this way. I understand that employee.Position in undefined and I don't know why. It seems like my array is populated with data because I can console.log(employee.Position) or (employee.Position.PositionName) it gives nice output. –  Dec 24 '17 at 21:49
  • This is asynchronous, so your variable is undefined initially when template is rendered. So when angular is trying to read property names, it's of course going to throw errors since there are no property names on `undefined`. SInce you are using `ngModel`, try one-way-binding with `ngModelChange`: https://stackoverflow.com/a/39755385/7741865 – AT82 Dec 25 '17 at 08:42

0 Answers0