<div *ngIf="true" myHighlight #tRefVar="myHighlight"></div>
<div>tRefVar is {{tRefVar.foo}}</div>
即使*ngIf
成立,我也会获得Cannot read property 'foo' of undefined
。如果我删除*ngIf
,它就可以了!
我尝试使用Elvis运算符tRefVar?.foo
来解决错误,但之后它永远不会使用值进行更新。
https://plnkr.co/edit/5rsXygxK1sBbbkYdobjn?p=preview
我做错了什么?
答案 0 :(得分:25)
正如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
答案 1 :(得分:1)
<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>
的兄弟
更多解释here
由于Child / Sibling元素可以引用模板引用变量,因此可以预期该行为。
答案 2 :(得分:0)
您可以使用例如ng-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
可能有更多方法可以让它发挥作用,但你必须更具体,然后你想用它做什么。
希望我能提供帮助。
要回答评论中的问题&#34; 不应该在第一次打勾后更新tRefVar吗?&#34; :
不,因为它未定义。如果在组件中声明对象(但保留未定义)并向其添加属性,则会得到相同的结果。 elvis运营商在那里没有帮助。
myObj: any;
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
这不会奏效,但这可行:
myObj: any = {};
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
再次编辑我的答案并删除了一个简单错误的令人困惑的解释。谢谢yurzui,终于得到了你的意思。需要一夜的睡眠。
答案 3 :(得分:0)
由@lexith在above answer中给出,因为您正在使用*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>
`,
})
答案 4 :(得分:0)
如果您使用的是Angular 8,则可以通过添加视图子引用并将静态值设置为false
来解决此问题。
示例模板代码:
<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
将是默认值。