<div *ngIf="true" myHighlight #tRefVar="myHighlight"></div>
<div>tRefVar is {{tRefVar.foo}}</div>
即使
*ngIf
为真,我仍然会收到Cannot read property 'foo' of undefined
的错误。如果我删除*ngIf
,它就可以正常工作! 我尝试使用Elvis运算符tRefVar?.foo
,它解决了错误,但它永远不会更新值。
我做错了什么?<div *ngIf="true" myHighlight #tRefVar="myHighlight"></div>
<div>tRefVar is {{tRefVar.foo}}</div>
*ngIf
为真,我仍然会收到Cannot read property 'foo' of undefined
的错误。如果我删除*ngIf
,它就可以正常工作! 我尝试使用Elvis运算符tRefVar?.foo
,它解决了错误,但它永远不会更新值。
我做错了什么?正如Tobias Bosch所说
* ngIf内声明的变量不能在*ngIf外部使用
https://github.com/angular/angular/issues/6179#issuecomment-233374700
只有相反的方式(即在*ngIf内部声明一个变量并在*ngIf外部使用它)是不起作用的,并且这是设计上不要这样做。
https://github.com/angular/angular/issues/6179#issuecomment-233579605
1)没有*ngIf
让我们来看一下这个模板
<h2 myHighlight #tRefVar="myHighlight">tRefVar is {{tRefVar.foo}}</h2>
<div>tRefVar is {{tRefVar?.foo}}</div>
Angular会为此创建以下viewDefinition
:
function View_App_0(_l) {
return jit_viewDef1(0,[(_l()(),jit_textDef2(null,['\n '])),(_l()(),jit_elementDef3(0,
null,null,2,'h2',[['myHighlight','']],null,null,null,null,null)),jit_directiveDef4(16384,
[['tRefVar',4]],0,jit_HighlightDirective5,[jit_ElementRef6],null,null),(_l()(),
jit_textDef2(null,['tRefVar is ',''])),(_l()(),jit_textDef2(null,['\n '])),
(_l()(),jit_elementDef3(0,null,null,1,'div',[],null,null,null,null,null)),(_l()(),
jit_textDef2(null,['tRefVar is ',''])),(_l()(),jit_textDef2(null,['\n ']))],
null,function(_ck,_v) {
var currVal_0 = jit_nodeValue7(_v,2).foo;
_ck(_v,3,0,currVal_0);
var currVal_1 = ((jit_nodeValue7(_v,2) == null)? null: jit_nodeValue7(_v,2).foo);
_ck(_v,6,0,currVal_1);
});
}
这里没有嵌入式视图。全部都在一个名为View_App_0
的视图中。我们可以看到这里的表达式是{{tRefVar?.foo}}
var currVal_1 = ((jit_nodeValue7(_v,2) == null)? null: jit_nodeValue7(_v,2).foo);
它从索引为2的节点获取值。
jit_directiveDef4(16384,
[['tRefVar',4]],0,jit_HighlightDirective5,[jit_ElementRef6],null,null),(_l()(),
jit_textDef2(null,['tRefVar is ','']))
在同一视图中声明的内容
2) 使用*ngIf指令
然后让我们按照以下方式更改模板
<h2 *ngIf="true" myHighlight #tRefVar="myHighlight">tRefVar is {{tRefVar.foo}}</h2>
<div>tRefVar is {{tRefVar?.foo}}</div>
输出结果如下:
function View_App_1(_l) {
return jit_viewDef1(0,[(_l()(),jit_elementDef2(0,null,null,2,'h2',[['myHighlight',
'']],null,null,null,null,null)),jit_directiveDef3(16384,[['tRefVar',4]],0,jit_HighlightDirective4,
[jit_ElementRef5],null,null),(_l()(),jit_textDef6(null,['tRefVar is ','']))],
null,function(_ck,_v) {
var currVal_0 = jit_nodeValue7(_v,1).foo;
_ck(_v,2,0,currVal_0);
});
}
function View_App_0(_l) {
return jit_viewDef1(0,[(_l()(),jit_textDef6(null,['\n'])),(_l()(),jit_anchorDef8(16777216,
null,null,1,null,View_App_1)),jit_directiveDef3(16384,null,0,jit_NgIf9,[jit_ViewContainerRef10,
jit_TemplateRef11],{ngIf:[0,'ngIf']},null),(_l()(),jit_textDef6(null,['\n'])),
(_l()(),jit_elementDef2(0,null,null,1,'div',[],null,null,null,null,null)),(_l()(),
jit_textDef6(null,['tRefVar is ',''])),(_l()(),jit_textDef6(null,['\n ']))],
function(_ck,_v) {
var currVal_0 = true;
_ck(_v,2,0,currVal_0);
},function(_ck,_v) {
var _co = _v.component;
var currVal_1 = ((_co.tRefVar == null)? null: _co.tRefVar.foo);
_ck(_v,5,0,currVal_1);
});
}
Angular创建了一个名为View_App_1
的嵌入式视图,与View_App_0
分开。我们的表达式{{tRefVar?.foo}}
已经变成:
var currVal_1 = ((_co.tRefVar == null)? null: _co.tRefVar.foo);
因为在View_App_0
中没有节点引用这个模板变量,所以它只成为了组件属性,并且被转移到嵌入式视图View_App_1
中。
var currVal_0 = jit_nodeValue7(_v,1).foo;
因此,我们无法在嵌入式视图之外引用已在嵌入式视图中声明的模板变量。
如何解决?
1)使用可见性标志,如[hidden]
或CSS类,而不是*ngIf
2)将您的表达式移动到声明tRefVar
的嵌入式视图内部。
<ng-container *ngIf="true">
<h2 myHighlight #tRefVar="myHighlight">tRefVar is {{tRefVar.foo}}</h2>
<div>tRefVar is {{tRefVar?.foo}}</div>
</ng-container>
3)使用@ViewChild
,因为它将表示组件属性。或使用@ViewChildren
ng-container
而不是ng-template
与ngIf
?如果两者都可以,那么在这种情况下选择它们的考虑因素是什么? - Alexander Abakumov<ng-template [ngIf]
代替,它甚至更好,因为它不会创建额外的注释节点。 - yurzuifalse
来解决此问题。<button type="button" (click)="eventsTable.someMethod()">Click Me!</button>
<div *ngIf="someValue" #eventsTable >
SHIBAMBO!
</div>
组件代码:
export class EventsComponent {
@ViewChild('eventsTable', {static: false}) eventsTable: Table;
constructor() {
console.log(this.eventsTable)
}
}
在Angular 9中,false
将是默认值。<div *ngIf="true" myHighlight #tRefVar="myHighlight"></div>
在这里您需要注意,*ngIf
是一个语法糖(快捷方式),用于定义一个ng-template
。因此,实际上它等价于:
<ng-template [ngIf]="true">
<h2 myHighlight #tRefVar="myHighlight">Hello {{name}}, tRefVar is {{tRefVar.foo}}</h2>
</ng-template>
<div>tRefVar is {{tRefVar?.foo}}</div>
#tRefVar
可以被子元素(div
)和本身(ng-template
)访问。<div>
不是存放模板引用变量的 <div>
的兄弟元素。tRefVar.foo
仍然在ng-template
的同级中,对吗?还是我漏掉了什么? - adamdportng-container
并将您的ngIf
条件设置在那里,这使得tRevVar
可以像这样访问:<ng-container *ngIf="true">
<h2 myHighlight #tRefVar="myHighlight">Hello {{name}}, tRefVar is {{tRefVar.foo}}</h2>
<div>tRefVar is {{tRefVar?.foo}}</div>
</ng-container>
Plunkr: https://plnkr.co/edit/cqrsDVGwa90o1FGWgE22?p=preview
可能有更多的方法可以使它工作,但是你必须更具体地说明你想要做什么。
希望我能帮到你。
myObj: any;
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
这个不行,但是这个会起作用:
myObj: any = {};
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
再次编辑了我的回答并删除了混淆视听、完全错误的解释。感谢yurzui,终于明白你的意思了。需要睡一晚上才能想清楚。
ng-template
块之外是不可用的。参考链接:https://dev59.com/r1oV5IYBdhLWcg3wIb74 https://github.com/angular/angular/issues/16262 - yurzuing-template
中插入了 {{tRefVar?.foo}}
。 - yurzui*ngIf
是ng-template [ngIf] =""
的快捷方式,但这不是他无法像他那样访问该值的原因。 - malifa如@lexith所述的上面的答案,因为您正在使用*ngIf
,相应的模板变量在此时未定义。我们可以通过修改代码来避免这种混淆
<div *ngIf="true" myHighlight #tRefVar="myHighlight"></div>
改为
<div [hidden]=false myHighlight #tRefVar="myHighlight"></div>
这样就可以正常工作了。
最终代码:
@Component({
selector: 'my-app',
template: `
<div>
<h2 [hidden]=false myHighlight #tRefVar="myHighlight">Hello {{name}}, tRefVar is {{tRefVar.foo}}</h2>
<div>tRefVar is {{tRefVar?.foo}}</div>
</div>
`,
})
[ngStyle]="{'display': showElement ? 'block' : 'none'}"
或使用任何其他默认的显示选项(flex,inline ...)。 - Andre Elrico