1

in my Angular project, I'm getting an error that says "cannot read property of '...' of undefined" where the '...' is the index of whichever employee that is selected from the combo box.

A little background on my project. I have the user select an employee from a combo box (tracker.component). Then, then index of that employee is taken and used to display the information of that employee (summary.component). It works great, along with having next, previous, first, last buttons but whenever I open the summary panel (summary.component) I get the error that I stated above in the browser. Where am I messing up?

Here's my tracker.component.ts

import { Component, OnInit, Input} from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { PTODataService } from './pto-data.service';
import { PTOData } from './pto-data';
import { EmpInfoService } from './emp-info.service';
import { EmpInfo } from './emp-info'; 

@Component({
    selector: 'pto-tracker',
    templateUrl: `./tracker.component.html`,
    styleUrls: ['./tracker.component.css']
})

export class TrackerComponent implements OnInit{
    empInfo: EmpInfo[] = new Array<EmpInfo>();
    ptoData: PTOData[];
    isHidden: boolean = false;
    selectedEmployee: number = 0;

    public selectedType: string = "PTO";

    constructor(
        private empInfoService: EmpInfoService,
        private ptoDataService: PTODataService) { }

    getEmpInfo(): void {
        this.empInfoService.getEmpInfos().then(
            empInfo => {
                this.empInfo = empInfo.sort((a, b) => a.LastName < b.LastName ? -1 : b.LastName < a.LastName ? 1 : 0);
            });
    }

    getPTOData(): void {
        this.ptoDataService.getPTODatas().then(
            ptoData => this.ptoData = ptoData
        );
    }

    ngOnInit(): void {
        this.getEmpInfo();
        this.getPTOData();
    }


    toggleSummary(): void {
        this.isHidden = !this.isHidden;
    }

    isNextValid() {
        if (this.selectedEmployee > 0) {
            return true;
        }
        else {
            return false;
        }
    }

    isPreviousValid() {
        if (this.selectedEmployee < this.empInfo.length - 1) {
            return true;
        }
        else {
            return false;
        }
    }

    nextEmployee(): void {
        this.selectedEmployee = this.selectedEmployee + 1;
    }

    previousEmployee(): void {
        this.selectedEmployee = this.selectedEmployee - 1;
    }

    firstEmployee(): void {
        this.selectedEmployee = 0;
    }

    lastEmployee(): void {
        this.selectedEmployee = this.empInfo.length - 1;
    }
}

my tracker.component.html

<div class="row">
  <div [ngClass]="{'col-xs-12':isHidden === true, 'col-xs-7': isHidden !== false}">
    <button class="btn btn-default btn-primary" style="width:50px; height: 50px; float:right; padding-bottom: 10px; padding-top: 10px;margin:5px;" (click)="toggleSummary()"><i class="fa fa-pencil-square-o fa-2x" aria-hidden="true"></i></button>

    <div class="col-xs-12 no-pad" style="padding-bottom:50px;">
      <div class="col-xs-3">
        <select class="form-control" id="empName" [(ngModel)]="selectedEmployee">
          <option selected="selected" disabled>Employee Name...</option>
          <option *ngFor="let emp of empInfo; let i = index" [ngValue]="i">{{i}} {{emp.EmpID}} - {{emp.FirstName}} {{emp.LastName}}</option>
        </select>
      </div>
      <div class="col-xs-2">
        <select class="form-control" id="PTOtype" [(ngModel)]="selectedType">
          <option selected="selected" value="PTO">PTO</option>
          <option value="etoEarned">ETO - Earned</option>
          <option value="etoUsed">ETO - Used</option>
          <option value="STDLTD">STD/LTD</option>
          <option value="Uncharged">Uncharged</option>
        </select>
      </div>
    </div>
    <div class="col-xs-12">
      <table class="table table-striped table-bordered">
        <thead>
          <tr>
            <th>Date</th>
            <th>Full/Half</th>
            <th>Hours</th>
            <th>Scheduled?</th>
            <th>Notes</th>
            <th>In P/R?</th>
          </tr>
        </thead>
        <tfoot *ngIf="empInfo && empInfo.length > selectedEmployee">
          <tr>
            <td colspan="6">
              <span class="requestText">Requests:</span>
              <button class="btn btn-default btn-primary btn-bargin" style="float: right;" (click)="lastEmployee()"><i class="fa fa-step-forward fa-lrg" aria-hidden="true"></i></button>
              <button [disabled]="!isPreviousValid()" class="btn btn-default btn-primary btn-margin" style="float:right;" (click)="nextEmployee()"><i class="fa fa-play fa-lrg" aria-hidden="true"></i></button>
              <div class="footertext">{{selectedEmployee+1}} of {{empInfo.length}}</div>
              <button [disabled]="!isNextValid()" class="btn btn-default btn-primary btn-margin" style="float: right;" (click)="previousEmployee()"><i class="fa fa-play fa-flip-horizontal fa-lrg" aria-hidden="true"></i></button>
              <button class="btn btn-default btn-primary btn-margin" style="float: right;" (click)="firstEmployee()"><i class="fa fa-step-backward fa-lrg" aria-hidden="true"></i></button>
            </td>
          </tr>
        </tfoot>
        <tbody>
          <tr *ngFor="let pto of ptoData">
            <ng-container *ngIf="pto.type === selectedType">
              <ng-container *ngIf="pto.EmpKey === empInfo[selectedEmployee].EmpKey">
                <td>{{pto.date | date: 'MM/dd/y'}}</td>
                <td>{{pto.fullhalf}}</td>
                <td>{{pto.hours}}</td>
                <td>{{pto.scheduled}}</td>
                <td>{{pto.notes}}</td>
                <td>{{pto.inPR}}</td>
              </ng-container>
            </ng-container>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
  <div *ngIf="isHidden" class="col-xs-5">
    <pto-summary [selectedEmployee]="selectedEmployee"></pto-summary>
  </div>
</div>

my summary.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EmpInfoService } from './emp-info.service';
import { TrackerComponent } from './tracker.component';
import { EmpInfo } from './emp-info'; 

@Component({
    selector: 'pto-summary',
    templateUrl: `./summary.component.html`,
    styleUrls: ['./summary.component.css']
})

export class SummaryComponent implements OnInit{

    empInfo: EmpInfo[];
    @Input() selectedEmployee: number;

    timeVar = " hours";
    checkboxValue = false;

    constructor(private empInfoService: EmpInfoService) { }

    getEmpInfo(): void {
        this.empInfoService.getEmpInfos().then(
            empInfo => {
                this.empInfo = empInfo.sort((a, b) => a.LastName < b.LastName ? -1 : b.LastName < a.LastName ? 1 : 0);
            });
    }

    ngOnInit(): void {
        this.getEmpInfo();
    }

    changeTime(): void {
        if (!this.checkboxValue)
        {
            this.timeVar = " hours"

            this.empInfo[this.selectedEmployee].STDLTD = this.empInfo[this.selectedEmployee].STDLTD * 8;
            this.empInfo[this.selectedEmployee].Uncharged = this.empInfo[this.selectedEmployee].Uncharged * 8;

            this.empInfo[this.selectedEmployee].PTOBase = this.empInfo[this.selectedEmployee].PTOBase * 8;
            this.empInfo[this.selectedEmployee].PTOCarry = this.empInfo[this.selectedEmployee].PTOCarry * 8;
            this.empInfo[this.selectedEmployee].PTOBorrowed = this.empInfo[this.selectedEmployee].PTOBorrowed * 8;
            this.empInfo[this.selectedEmployee].PTOBalance = this.empInfo[this.selectedEmployee].PTOBalance * 8;
            this.empInfo[this.selectedEmployee].PTORequests = this.empInfo[this.selectedEmployee].PTORequests * 8;
            this.empInfo[this.selectedEmployee].PTORemaining = this.empInfo[this.selectedEmployee].PTORemaining * 8;

            this.empInfo[this.selectedEmployee].ETOEarned = this.empInfo[this.selectedEmployee].ETOEarned * 8;
            this.empInfo[this.selectedEmployee].ETORequests = this.empInfo[this.selectedEmployee].ETORequests * 8;
            this.empInfo[this.selectedEmployee].ETORemaining = this.empInfo[this.selectedEmployee].ETORemaining * 8;
        }
        else
        {
            this.timeVar = " days"

            this.empInfo[this.selectedEmployee].STDLTD = this.empInfo[this.selectedEmployee].STDLTD / 8;
            this.empInfo[this.selectedEmployee].Uncharged = this.empInfo[this.selectedEmployee].Uncharged / 8;

            this.empInfo[this.selectedEmployee].PTOBase = this.empInfo[this.selectedEmployee].PTOBase / 8;
            this.empInfo[this.selectedEmployee].PTOCarry = this.empInfo[this.selectedEmployee].PTOCarry / 8;
            this.empInfo[this.selectedEmployee].PTOBorrowed = this.empInfo[this.selectedEmployee].PTOBorrowed / 8;
            this.empInfo[this.selectedEmployee].PTOBalance = this.empInfo[this.selectedEmployee].PTOBalance / 8;
            this.empInfo[this.selectedEmployee].PTORequests = this.empInfo[this.selectedEmployee].PTORequests / 8;
            this.empInfo[this.selectedEmployee].PTORemaining = this.empInfo[this.selectedEmployee].PTORemaining / 8;

            this.empInfo[this.selectedEmployee].ETOEarned = this.empInfo[this.selectedEmployee].ETOEarned / 8;
            this.empInfo[this.selectedEmployee].ETORequests = this.empInfo[this.selectedEmployee].ETORequests / 8;
            this.empInfo[this.selectedEmployee].ETORemaining = this.empInfo[this.selectedEmployee].ETORemaining / 8;
        }
    }
}

and my summary.component.html

<div class="panel panel-default">
  <div class="panel-heading">
    <h3 class="panel-title pull-left">{{empInfo[selectedEmployee].LastName | uppercase}} Summary</h3>
    <div style="float: right;">
      <div class="onoffswitch">
        <input [(ngModel)]="checkboxValue" (change)="changeTime()" type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch" checked>
        <label class="onoffswitch-label" for="myonoffswitch">
          <span class="onoffswitch-inner"></span>
          <span class="onoffswitch-switch"></span>
        </label>
      </div>
    </div>
    <div class="clearfix"></div>
  </div>
  <div class="panel-body">
    <form class="form-horizontal" role="form" style="overflow-x:auto;">
      <fieldset>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-5"> Status </label>
            <div class="col-xs-7">
              <select class="form-control" id="empStatus" [(ngModel)]="empInfo[selectedEmployee].EmpStat" name="empStatus">
                <option value="Current">Current</option>
                <option value="Terminated">Terminated</option>
              </select>
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-5"> Anniversary </label>
            <div class="col-xs-7">
              <div class="input-group">
                <input class='form-control' type="text" id="empAnniversary" [(ngModel)]="empInfo[selectedEmployee].Anniversary" name="empAnniversary" />
                <span class="input-group-addon">years</span>
              </div>
            </div>
          </div>
         </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-5"> Start Date </label>
            <div class="col-xs-7">
              <input class='form-control' type="text" id="empStartDate" [ngModel]="empInfo[selectedEmployee].StartDate | date: 'MM/dd/y'" name="empStartDate"/>
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-5"> Adjusted Start </label>
            <div class="col-xs-7">
              <input class='form-control' type="text" id="empAdjustedStart" [ngModel]="empInfo[selectedEmployee].AdjustedStart | date: 'MM/dd/y'" name="empAdjustedStart"/>
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-5"> STD/LTD </label>
            <div class="col-xs-7">
              <div class="input-group">
                <input class='form-control' type="text" id="empSTDLTD" [(ngModel)]="empInfo[selectedEmployee].STDLTD" name="empSTDLTD" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-5"> Uncharged </label>
            <div class="col-xs-7">
              <div class="input-group">
                <input class='form-control' type="text" id="empUncharged" [(ngModel)]="empInfo[selectedEmployee].Uncharged" name="empUncharged" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
          </div>
        </div>
      </fieldset>


      <fieldset>

        <h4>PTO</h4>
        <br />

        <div class="col-xs-12">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <div class="col-xs-1"></div>
            <label class="col-xs-2"> Base </label>
            <div class="col-xs-3">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoBase" [(ngModel)]="empInfo[selectedEmployee].PTOBase" name="ptoBase" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
            <div class="col-xs-6">
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-2" style="font-weight: bold;"> &#43; </label>
            <label class="col-xs-4"> Carryover </label>
            <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoCarry" [(ngModel)]="empInfo[selectedEmployee].PTOCarry" name="ptoCarry" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <div class="col-xs-1"></div>
            <label class="col-xs-4"> Balance </label>
            <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoBalance" [(ngModel)]="empInfo[selectedEmployee].PTOBalance" name="ptoBalance" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
            <div class="col-xs-1"></div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-2" style="font-weight: bold;"> &#8213; </label>
            <label class="col-xs-4"> Borrowed </label>
            <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoBorrowed" [(ngModel)]="empInfo[selectedEmployee].PTOBorrowed" name="ptoBorrowed" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
          </div>
          <hr style="border: solid 1px black;border-bottom:1px solid black;clear:both" />
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-1" style="font-weight: bold;"> &#8213; </label>
            <label class="col-xs-4"> Requests </label>
            <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoRequests" [(ngModel)]="empInfo[selectedEmployee].PTORequests" name="ptoRequests" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
            <div class="col-xs-1"></div>
          </div>
          <hr style="border: solid 1px black;border-bottom:1px solid black;clear:both" />
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-2" style="font-weight: bold;"> &#61; </label>
            <label class="col-xs-4"> Balance </label>
            <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoBalance" [(ngModel)]="empInfo[selectedEmployee].PTOBalance" name="ptoBalance" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="col-xs-6">
          <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
            <label class="col-xs-1" style="font-weight: bold;"> &#61; </label>
            <label class="col-xs-4"> Available </label>
            <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="ptoRemaining" [(ngModel)]="empInfo[selectedEmployee].PTORemaining" name="ptoRemaining" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
            </div>
            <div class="col-xs-1"></div>
          </div>
        </div>
      </fieldset>


      <fieldset>

        <h4>ETO</h4>
        <br />

          <div class="col-xs-6">
            <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
              <div class="col-xs-2"></div>
              <label class="col-xs-4"> Earned </label>
              <div class="col-xs-6">
                <div class="input-group">
                  <input class='form-control' type="text" id="etoEarned" [(ngModel)]="empInfo[selectedEmployee].ETOEarned" name="etoEarned" />
                  <span class="input-group-addon">{{timeVar}}</span>
                </div>
              </div>
            </div>
            <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
              <label class="col-xs-2"> &#8213; </label>
              <label class="col-xs-4"> Requests </label>
              <div class="col-xs-6">
              <div class="input-group">
                <input class='form-control' type="text" id="etoRequests" [(ngModel)]="empInfo[selectedEmployee].ETORequests" name="etoRequests" />
                <span class="input-group-addon">{{timeVar}}</span>
              </div>
              </div>
            </div>
            <hr style="border: solid 1px black;border-bottom:1px solid black;clear:both" />
            <div class="form-group" *ngIf="empInfo && empInfo.length > selectedEmployee">
              <label class="col-xs-2"> &#61; </label>
              <label class="col-xs-4"> Available </label>
              <div class="col-xs-6">
                <div class="input-group">
                  <input class='form-control' type="text" id="etoRemaining" [(ngModel)]="empInfo[selectedEmployee].ETORemaining" name="etoRemaining" />
                  <span class="input-group-addon">{{timeVar}}</span>
                </div>
              </div>
            </div>
          </div>
          <div class="col-xs-6"></div>

      </fieldset>
    </form>
  </div>
</div>

2
  • I assume based on the message that the problem is here: {{empInfo[selectedEmployee].LastName | uppercase}} I'm not sure you can use the safe navigation operation on an array index. Commented Jun 7, 2017 at 14:55
  • @DeborahK yeah I checked and it says that's the line that it's having a problem with Commented Jun 7, 2017 at 14:58

1 Answer 1

5

I assume based on the message that the problem is here: {{empInfo[selectedEmployee].LastName | uppercase}}

If your service is using Http, then it is an asynchronous operation. That means that your page is trying to display before the data is available.

There are several common ways to resolve this issue, but your best bet may be to add an *ngIf in your HTML to check whether you have data before displaying the page.

Something like you already did here:

*ngIf="empInfo && empInfo.length
Sign up to request clarification or add additional context in comments.

Comments

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.