Angular mat Dialog无法显示对象属性值问题排查
Angular Material mat-dialog对象属性无法读取问题排查
问题现象
使用Angular Material的mat-dialog组件时遇到对象数据无法正常展示的问题:在普通div标签中配合*ngIf指令使用时数据可正常渲染,但结合mat-dialog与ng-template使用时,若不添加*ngIf判断,程序无法识别对象属性值,报错信息如下:
Object is possibly 'undefined'.ngtsc(2532)
cyclers.component.ts(9, 6): Error occurs in the template of component CyclersComponent.
若移除*ngIf判断,不在模板中读取selectedTeam.teamName、selectedTeam.teamDescription属性,而是直接渲染selectedTeam变量,页面会输出[Object Object]。
相关代码
HTML模板
<div class="main"> <h2>Cycling Teams</h2> <div class="container"> <div class="team" *ngFor="let team of teams;"> <img src="{{ team.teamImage }}"[class.selected]="team === selectedTeam" (click)="expandRiders(team)"> <h2>{{team.teamName}}</h2> </div> <ng-template #riderDescription> <mat-dialog-content> <h2 style="text-align: center ;" mat-dialog-title>{{ selectedTeam.teamName }}</h2> <p mat-typography style="text-align: left;">{{ selectedTeam.teamDescription}}</p> </mat-dialog-content> <mat-dialog-actions> <button mat-button mat-dialog-close>Cancel</button> </mat-dialog-actions> </ng-template> </div> </div>
Typescript组件代码
import { Team } from './../team'; import { TEAMS } from './../list-cyclers'; import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; import { MatDialog, MatDialogContent, MatDialogConfig } from '@angular/material/dialog'; @Component({ selector: 'app-cyclers', templateUrl: './cyclers.component.html', styleUrls: ['./cyclers.component.css'] }) export class CyclersComponent implements OnInit { @ViewChild ('riderDescription') riderDescription: TemplateRef<any>; teams = TEAMS; selectedTeam?: Team; constructor(public dialog: MatDialog) { } ngOnInit(): void { } expandRiders(team: Team){ this.dialog.open(this.riderDescription); this.selectedTeam = team; console.log(this.selectedTeam); } }
问题产生原因
- TS静态类型校验限制:组件中
selectedTeam被声明为可选属性selectedTeam?: Team,TS默认认为该变量初始值为undefined,直接访问其属性时就会触发Object is possibly 'undefined'类型错误。普通div中配合*ngIf使用时,*ngIf本身做了存在性判断,TS会自动做类型收窄,判定块级作用域内selectedTeam一定有值,因此不会报错。 - 代码执行顺序错误:
expandRiders方法中先执行了弹窗打开逻辑this.dialog.open(this.riderDescription),之后才给this.selectedTeam赋值。弹窗创建时会立即完成模板首次渲染,此时selectedTeam还未被赋值,自然读不到对应属性。 - 默认类型转换行为:直接渲染对象变量时,Angular插值表达式会默认将值转为字符串,普通JavaScript对象转字符串的结果就是
[object Object],属于正常表现,和组件本身bug无关。
修复方案
按照以下步骤调整即可解决问题:
- 调换方法内代码执行顺序,先给
selectedTeam赋值,再打开弹窗,保证弹窗渲染时变量已经完成赋值:
expandRiders(team: Team){ this.selectedTeam = team; // 先赋值 this.dialog.open(this.riderDescription); // 后打开弹窗 }
- 解决TS类型校验报错,二选一即可:
- 方案A:在模板属性访问时使用可选链操作符
?.做安全访问,即使变量为undefined也不会抛出错误:<h2 mat-dialog-title>{{ selectedTeam?.teamName }}</h2> <p mat-typography>{{ selectedTeam?.teamDescription}}</p> - 方案B:在弹窗内容外层加
*ngIf做存在性守卫,和普通div的用法保持一致,只有selectedTeam有值时才渲染弹窗内容:<ng-template #riderDescription> <ng-container *ngIf="selectedTeam"> <mat-dialog-content> <h2 style="text-align: center;" mat-dialog-title>{{ selectedTeam.teamName }}</h2> <p mat-typography style="text-align: left;">{{ selectedTeam.teamDescription}}</p> </mat-dialog-content> <mat-dialog-actions> <button mat-button mat-dialog-close>Cancel</button> </mat-dialog-actions> </ng-container> </ng-template>
- 方案A:在模板属性访问时使用可选链操作符
内容的提问来源于stack exchange,提问作者Johny
相关产品推荐
相关产品推荐

