0

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
  • 1
    Have you tried ptoData: PTOData[] = [];? Commented Jun 20, 2017 at 12:35

1 Answer 1

4

You need to initialize the array,

ptoData: PTOData[] = [];
Sign up to request clarification or add additional context in comments.

3 Comments

that works, I feel dumb now haha. But, whenever I push the button, nothing in my table updates. Why would that be?
where is the table?
I'll add those files to the OP. My table is in the row-display component which is inside the grid component which is called inside the file I posted originally

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.