Angular中点击span调用tooltip-icon的showMessage方法时tooltip为undefined的问题
问题根因
之前代码里点击用户名时拿不到tooltip实例的原因很直接:
- 你把
#tooltip这个模板引用变量挂在了带*ngIf的<tooltip-icon>元素上,这个元素处于*ngIf生成的独立内嵌视图里,外面的<span>和它不在同一个渲染视图作用域,根本访问不到这个变量,传进方法的参数自然就是undefined - 循环列表场景下直接复用同一个模板变量名,也没法精准绑定到当前行的tooltip组件,哪怕能跨作用域访问,最后也只会拿到列表最后一行的组件实例
两种可落地的解决方案
方案1:统一作用域,直接绑定引用
把同一张卡片内的用户名和错误提示组件放到同一个*ngIf视图块内,让两个元素处于相同的作用域,直接调用组件实例方法即可,不需要额外的透传逻辑:
<div class="users-cards"> <div *ngFor="let user of users" class="card"> <!-- 错误状态的用户:把span和tooltip放到同一个ngIf视图内 --> <ng-container *ngIf="user.status === 'err'; else normalUser"> <span (click)="errTooltip.showMessage()">{{ user.name }}</span> <tooltip-icon [label]="user.msg" #errTooltip ></tooltip-icon> </ng-container> <!-- 正常状态的用户:单独渲染用户名 --> <ng-template #normalUser> <span>{{ user.name }}</span> </ng-template> </div> </div>
这种方式完全不需要在组件类里额外写判断逻辑,因为只有err状态的用户才会进入对应的视图块,点击用户名时直接拿到同视图下的tooltip实例调用showMessage()即可。
方案2:用ViewQueries批量获取实例
如果不想调整原模板的DOM结构,可以在组件类里通过查询获取所有tooltip组件的实例,根据用户的唯一标识匹配对应行的实例调用方法:
// 引入对应装饰器和组件类型 import { ViewChildren, QueryList } from '@angular/core'; import { TooltipIconComponent } from './tooltip-icon.component'; // 批量获取页面上所有的tooltip-icon组件实例 @ViewChildren(TooltipIconComponent) tooltipList: QueryList<TooltipIconComponent>; showTooltip(user: UserItem) { // 非错误状态的用户直接跳过 if (user.status !== 'err') return; // 根据用户唯一id匹配对应行的tooltip实例 const targetTooltip = this.tooltipList.find(item => item.boundUser.id === user.id); // 实例存在时再调用方法,避免空指针报错 targetTooltip?.showMessage(); }
对应模板里去掉多余的参数透传,直接传当前行的user对象即可:
<div class="users-cards"> <div *ngFor="let user of users" class="card"> <span (click)="showTooltip(user)">{{ user.name }}</span> <tooltip-icon *ngIf="user.status=='err'" [boundUser]="user" [label]="user.msg" ></tooltip-icon> </div> </div>
注意:这种方式需要给<tooltip-icon>组件传入对应的user绑定对象,才能正确匹配到对应行的实例
常见踩坑提醒
不要跨结构指令的独立视图访问模板引用变量。
*ngIf、*ngSwitch这类结构指令会生成独立的内嵌渲染视图,视图内部定义的模板引用变量仅在当前视图内可访问,外层同级节点直接引用一定会拿到undefined值。
内容的提问来源于stack exchange,提问作者Kamil Kiełczewski
相关产品推荐
相关产品推荐

