user11352561
user11352561

Reputation: 2647

Angular - ERROR TypeError: Cannot read properties of undefined (reading 'licence_number')

In my Angular-12 I have this code:

And your JSON is invalid. It should be as below:

{
  "message": "Employee Detail.",
  "error": false,
  "code": 200,
  "results": {
    "employee": {
      "id": 8,
      "first_name": "JONAH",
      "last_name": "YAKUBU",
      "other_name": "STANLEY",
      "licences": [
        {
          "id": 1,
          "licence_number": "dsdsdsd"
        }
      ]
    }
  }
}

interface:

export class EmployeeResponse {
  results!: { employee: IEmployee };
}

export interface IEmployee {
  id?: number;
  first_name: string;
  other_name: string;
  last_name: string;
  licence_number?: string;
  licences?: ILicence[];
}

export interface ILicence {
  id: number;
  licence_number: string;
  dl_classification_id: number;
  licenceclass?: {id:number,class_name:string};
}

service:

  getEmployeeById(id: number): Observable<EmployeeResponse> {
    return this.http.get('/assets/data.json').pipe(
      map((response: any) => {
        if (!response) return response;

        if (!response.results) return response;

        if (!response.results.employee) return response;

        let employee: IEmployee = {
          ...response.results.employee,
          licence_number:
            response.results.employee.licences &&
            response.results.employee.licences[0].licence_number
        };

        response.results.employee = employee;

        return response;
      })
    );
  }

component:

export class AppComponent {
  profileInfoForm!: FormGroup;
  licenceInfoForm!: FormGroup;

  profileTemplate: boolean = true;
  licenceTemplate: boolean = false;

  isLoading = false;
  employee: IEmployee;
  _id = 1;

  constructor(
    private fb: FormBuilder,
    private employeeService: EmployeeService
  ) {}

  ngOnInit(): void {
    this.isLoading = true;
    //this._id = this.route.snapshot.params['id'];
    this.updateEmployee();
    this.updateLicence();
    this.loadEmployeeById();
  }

  profileFunction() {
    this.profileTemplate = true;
    this.licenceTemplate = false;
  }

  licenceFunction() {
    this.profileTemplate = false;
    this.licenceTemplate = true;
  }

  updateEmployee() {
    this.profileInfoForm = this.fb.group({
      id: [''],
      first_name: [
        '', [Validators.required, Validators.minLength(2), Validators.maxLength(50)]
      ],
      other_name: ['', [Validators.maxLength(50)]],
      last_name: [
        '', [Validators.required, Validators.minLength(2), Validators.maxLength(50)]
      ]
    });
  }

  updateLicence() {
    this.licenceInfoForm = this.fb.group({
      id: [''],
      licence_number: ['', [Validators.required, Validators.minLength(2)]]
    });
  }

  get fp() {
    return this.profileInfoForm.controls;
  }
  get fl() {
    return this.licenceInfoForm.controls;
  }

  profileValidate() {
    if (!this.profileInfoForm.valid) {
      this.profileInfoForm.markAllAsTouched();
      return;
    }
  }

  licenceValidate() {
    if (!this.licenceInfoForm.valid) {
      this.licenceInfoForm.markAllAsTouched();
      return;
    }
  }

  loadEmployeeById() {
    this.employeeService
      .getEmployeeById(this._id)
      .subscribe((data: EmployeeResponse) => {
        console.log(data.results.employee)
        this.employee = data.results.employee;
        this.profileInfoForm.patchValue({
          first_name: this.employee.first_name,
          other_name: this.employee.other_name,
          last_name: this.employee.last_name
        });
        this.licenceInfoForm.patchValue({
          licence_number: this.employee.licence_number
        });
      });
  }
}
<div class="col-md-3">
  <div class="sticky-top mb-3">
    <div class="card">
      <div class="card-header">
        <h4 class="card-title">Click to Edit</h4>
      </div>
      <div class="card-body">
        <div id="external-events">
          <button (click)="profileFunction()" type="button" class="btn btn-block btn-primary">Profile</button>
          <button (click)="licenceFunction()" type="button" class="btn btn-block btn-warning">Licence</button>
        </div>
      </div>
      <div class="card-header">
      </div>

    </div>
  </div>
</div>

<div class="col-md-9" *ngIf="employee != undefined">
  <div *ngIf="profileTemplate" class="card card-default color-palette-box">
    <div class="card-body">
      <form [formGroup]="profileInfoForm" (ngSubmit)="onSubmitProfile()">
        <div class="row">
          <div class="col-md-12">
            <div class="row">
              <div class="col-12 col-md-4">
                <div class="form-group">
                  <label for="first_name">First Name:<span style="color:red;">*</span></label>
                  <input type="text" formControlName="first_name" placeholder="First Name" class="form-control" required/>
                </div>
                <div *ngIf="fp.first_name.touched && fp.first_name.invalid">
                  <div *ngIf="fp.first_name.hasError('required')">
                    <div class="text-danger">
                      First Name is required!
                    </div>
                  </div>
                  <div *ngIf="fp.first_name.hasError('minlength')">
                    <div class="text-danger">
                      First Name cannot be less than 2 characters!
                    </div>
                  </div>
                  <div *ngIf="fp.first_name.hasError('maxlength')">
                    <div class="text-danger">
                      First Name cannot be more than 50 characters!
                    </div>
                  </div>
                </div>
              </div>
              <div class="col-12 col-md-4">
                <div class="form-group">
                  <label for="other_name">Middle Name:<span style="color:red;">*</span></label>
                  <input type="text" formControlName="other_name" placeholder="Middle Name" class="form-control" required/>
                </div>
                <div *ngIf="fp.other_name.touched && fp.other_name.invalid">
                  <div *ngIf="fp.other_name.hasError('maxlength')">
                    <div class="text-danger">
                      Middle Name cannot be more than 50 characters!
                    </div>
                  </div>
                </div>
              </div>
              <div class="col-12 col-md-4">
                <div class="form-group">
                  <label for="last_name">Last Name:<span style="color:red;">*</span></label>
                  <input type="text" formControlName="last_name" placeholder="Last Name" class="form-control" required/>
                </div>
                <div *ngIf="fp.last_name.touched && fp.last_name.invalid">
                  <div *ngIf="fp.last_name.hasError('required')">
                    <div class="text-danger">
                      Last Name is required!
                    </div>
                  </div>
                  <div *ngIf="fp.last_name.hasError('minlength')">
                    <div class="text-danger">
                      Last Name cannot be less than 2 characters!
                    </div>
                  </div>
                  <div *ngIf="fp.last_name.hasError('maxlength')">
                    <div class="text-danger">
                      Last Name cannot be more than 50 characters!
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="card-footer">
          <button type="submit" class="btn btn-success" [disabled]="isLoading" class="btn btn-success" (click)="profileValidate()">
                    <span *ngIf="isLoading" class="spinner-border spinner-border-sm mr-1"></span>
                    <i class="fa fa-save" aria-hidden="true"></i> Save</button>
        </div>
      </form>
    </div>
  </div>
  <div *ngIf="licenceTemplate" class="card card-default color-palette-box">
    <form [formGroup]="licenceInfoForm" (ngSubmit)="onSubmitLicence()">
      <div class="row">
        <div class="col-12 col-md-6">
          <div class="form-group">
            <label for="licence_number">Licence Number:<span style="color:red;">*</span></label>
            <input type="text" formControlName="licence_number" placeholder="Licence Number" class="form-control" required/>
          </div>
          <div *ngIf="fl.licence_number.touched && fl.licence_number.invalid">
            <div *ngIf="fl.licence_number.hasError('required')">
              <div class="text-danger">
                Licence Number is required!
              </div>
            </div>
            <div *ngIf="fl.licence_number.hasError('minlength')">
              <div class="text-danger">
                Licence Number cannot be less than 2 characters!
              </div>
            </div>
            <div *ngIf="fl.licence_number.hasError('maxlength')">
              <div class="text-danger">
                Licence Number cannot be more than 50 characters!
              </div>
            </div>
          </div>
        </div>
        <div class="card-footer">
          <button type="submit" class="btn btn-success" [disabled]="isLoading" class="btn btn-success" (click)="licenceValidate()">
                    <span *ngIf="isLoading" class="spinner-border spinner-border-sm mr-1"></span>
                    <i class="fa fa-save" aria-hidden="true"></i> Save</button>
        </div>
      </div>
    </form>
  </div>
</div>

Initially, everything was working fine but suddenly, I got this error:

ERROR TypeError: Cannot read properties of undefined (reading 'licence_number')

which is coming from the service.

How do I resolve this?

Thanks.

ERROR TypeError: Cannot read properties of undefined (reading 'licence_number')

Upvotes: 4

Views: 94048

Answers (3)

Alan Naicson
Alan Naicson

Reputation: 59

if you are checking like ngIf="someArray[0]?

then you should initialize your array on your component like this: someArray: any[] = []

if you just declare someArray: any[] it will give the error

Upvotes: 1

Panagiotis Bougioukos
Panagiotis Bougioukos

Reputation: 19173

let employee: IEmployee = {
    ...response.results.employee,
    licence_number:
                 (response.results.employee.licences &&
                  response.results.employee.licences[0] &&
                  response.results.employee.licences[0].licence_number ) 
                  ? response.results.employee.licences[0].licence_number : '';

Try to check better if the field is there and if not then provide an empty string ''

Here is a simple example why your checks are not enough.

const c = {d: []}
console.log(c.d);   // -> prints []
console.log(c.d[0]); // -> prints undefined

You can also understand that is important to always patch the value with something. So if in the end the value you try to patch is undefined, it will fail. In that case you must first check and if undefined then patch it with an empty string ''.

Upvotes: 3

Den
Den

Reputation: 786

I think or you read the wrong JSON or enter in one of this case...

if (!response) return response;

        if (!response.results) return response;

        if (!response.results.employee) return response;

Try to change this code into this

if (!response) return response;

        if (!response['results']) return response;

        if (!response['results']['employee']) return response;

Upvotes: 1

Related Questions