Angular - TypeError: cannot read property 'push' of undefined

时间:2017-06-20 12:34:24

标签: angular typeerror

In my Angular program, I'm trying to implement a button to add a row to my table and whenever I run it, I'm getting an error in the browser that says "ERROR TypeError: Cannot read property 'push' of undefined" I have my array defined so I'm not quite sure why this is happening. Thanks!

Here's my .ts file

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;
    currentDay: Date = new Date;

    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);
            });
    }

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


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

    onNotify(index: number) {
        this.selectedEmployee = index;
    }

    addRow(): void {
        this.ptoData.push({
            ID: this.selectedEmployee,
            EmpKey: EmpInfo[this.selectedEmployee].EmpKey,
            type: this.selectedType,
            date: this.currentDay,
            fullhalf: '',
            hours: 0,
            scheduled: '',
            notes: '',
            inPR: false,
            prDate: this.currentDay
        })
    }
}

and here's my html (just in case):

<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">{{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>
        <button class="btn btn-default btn-margin" style="float: left;" (click)="addRow()"><i class="fa fa-plus" aria-hidden="true"></i></button>
      </div>
    </div>
    <div class="col-xs-12">
      <pto-grid [selectedType]="selectedType" [selectedEmployee]="selectedEmployee" (notify)="onNotify($event)"></pto-grid>
    </div>
  </div>
  <div *ngIf="isHidden" class="col-xs-5">
    <pto-summary [selectedEmployee]="selectedEmployee" ></pto-summary>
  </div>
</div>

Here's my grid.component.ts:

import { Component, OnInit, EventEmitter, Input, Output, Pipe } 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';
import { TrackerComponent } from './tracker.component';

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

export class GridComponent implements OnInit {

    empInfo: EmpInfo[];
    ptoData: PTOData[];

    @Input() selectedEmployee: number;
    @Input() selectedType: string;

    @Output() notify = new EventEmitter<number>();

    rowSelected: number;

    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();
    }

    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;
        this.notify.emit(this.selectedEmployee);
    }

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

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

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

    isRowSelected(i: number) {
        return i == this.rowSelected;
    }

    selectRow(i: number) {
        this.rowSelected = i;
    }
}

My grid.component.html:

<table class="table table-striped table-bordered" *ngIf="empInfo && empInfo.length > selectedEmployee">
  <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>
    <tr>
      <td colspan="6">
        <span class="requestText">PTO Requests: {{empInfo[selectedEmployee].PTORequests}} hours / {{empInfo[selectedEmployee].PTORequests/8}} day(s)</span>
        <span class="requestText"> | </span>
        <span class="requestText">ETO Requests: {{empInfo[selectedEmployee].ETORequests}} hours / {{empInfo[selectedEmployee].ETORequests/8}} day(s)</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>
    <ng-container *ngFor="let pto of (ptoData | currentEmployee:empInfo[selectedEmployee].EmpKey); let i = index">
      <ng-container [ngSwitch]="isRowSelected(i)">
        <ng-container *ngSwitchCase="false">
          <ng-container *ngIf="pto.type === selectedType">
            <tr pto-row-display [pto]="pto" (click)="selectRow(i)"></tr>
          </ng-container>
        </ng-container>
        <ng-container *ngSwitchCase="true">
          <tr pto-row-edit [pto]="pto" *ngIf="pto.type === selectedType"></tr>
        </ng-container>
    </ng-container>
   </ng-container>
  </tbody>
</table>

My row-display.component.ts:

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

import { PTOData } from './pto-data';

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

export class RowDisplayComponent {
    @Input() pto: PTOData[];
}

and my row-display.component.html:

<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>
  <input class="form-check-input" type="checkbox" id="ptoinPR" [(ngModel)]="pto.inPR" name="ptoinPR" disabled/>
</td>

1 个答案:

答案 0 :(得分:3)

You need to initialize the array,

ptoData: PTOData[] = [];