Angular - 无法读取未定义的属性“..”

Posted

技术标签:

【中文标题】Angular - 无法读取未定义的属性“..”【英文标题】:Angular - Cannot Read Property '..' of undefined 【发布时间】:2017-11-09 00:11:33 【问题描述】:

在我的 Angular 项目中,我收到一条错误消息,提示“无法读取未定义的 '...' 的属性”,其中 '...' 是从组合框中选择的任何员工的索引。

我的项目的一点背景。我让用户从组合框(tracker.component)中选择一名员工。然后,获取该员工的索引并用于显示该员工的信息(summary.component)。它工作得很好,还有下一个、上一个、第一个、最后一个按钮,但是每当我打开摘要面板(summary.component)时,我都会收到上面在浏览器中所述的错误。我在哪里搞砸了?

这是我的 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;
    

我的 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>

我的 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;
        
    

还有我的 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>

【问题讨论】:

我假设问题出在这里:empInfo[selectedEmployee].LastName |大写我不确定你是否可以对数组索引使用安全导航操作。 @DeborahK 是的,我检查了,它说这是它有问题的行 【参考方案1】:

我根据问题所在的消息假设:empInfo[selectedEmployee].LastName | uppercase

如果您的服务使用 Http,那么它是一个异步操作。这意味着您的页面试图在数据可用之前显示

有几种常见的方法可以解决这个问题,但最好的办法是在 HTML 中添加一个 *ngIf 以在显示页面之前检查是否有数据。

你已经在这里做过的事情:

*ngIf="empInfo && empInfo.length

【讨论】:

以上是关于Angular - 无法读取未定义的属性“..”的主要内容,如果未能解决你的问题,请参考以下文章

Angular给出TypeError:“无法读取未定义的属性'id'”

Angular 6:TypeError:无法读取未定义的属性“值”

使用Angular 7获取“无法读取未定义的属性'http'”

无法读取未定义 Angular 6 的属性“nativeElement”

Angular 6 TypeError:无法读取未定义的属性(读取“长度”)错误

Angular 8:错误类型错误:无法读取未定义的属性“无效”