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>
答案 0 :(得分:3)
You need to initialize the array,
ptoData: PTOData[] = [];