如何将模板引用变量与 ngIf 结合使用?
How do I combine a template reference variable with ngIf?
<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
我做错了什么?
您可以使用例如 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>
笨蛋:https://plnkr.co/edit/cqrsDVGwa90o1FGWgE22?p=preview
可能有更多方法可以让它发挥作用,但你必须更具体,你想用它做什么。
希望我能帮到你。
要回答您评论中的问题“它不应该在第一次跳动后更新 tRefVar 吗?”:
不,因为它是未定义的。如果您在组件中声明一个对象(但保留它未定义)并向其添加 属性,您将获得相同的结果。 elvis 运算符在那里没有帮助。
myObj: any;
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
这行不通,但这会起作用:
myObj: any = {};
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
再次编辑了我的答案并删除了明显错误的令人困惑的解释。谢谢yurzui,终于明白你的意思了。它需要睡一夜。
<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
可由 Child(div
此处)及其自身(ng-template
此处)访问。
第二个 <div>
不是存在模板引用变量的 <div>
的兄弟。
更多解释here
该行为是预期的,因为 Child/Sibling 个元素可以引用模板引用变量。
如@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>
`,
})
正如 Tobias Bosch 所说
A variable declared inside of an *ngIf cannot be used outside of the
*ngIf
https://github.com/angular/angular/issues/6179#issuecomment-233374700
Only the opposite way (i.e. declare a variable inside of *ngIf and use
it outside of *ngIf) is not working, and won't work by design.
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 class 这样的可见性标志,而不是 *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
如果您使用的是 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)
}
}
在Angular9中,false
将是默认值。
<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
我做错了什么?
您可以使用例如 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>
笨蛋:https://plnkr.co/edit/cqrsDVGwa90o1FGWgE22?p=preview
可能有更多方法可以让它发挥作用,但你必须更具体,你想用它做什么。
希望我能帮到你。
要回答您评论中的问题“它不应该在第一次跳动后更新 tRefVar 吗?”:
不,因为它是未定义的。如果您在组件中声明一个对象(但保留它未定义)并向其添加 属性,您将获得相同的结果。 elvis 运算符在那里没有帮助。
myObj: any;
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
这行不通,但这会起作用:
myObj: any = {};
ngOnInit() {
myObj.text = 'my Text';
}
<div>{{ myObj?.text }}</div>
再次编辑了我的答案并删除了明显错误的令人困惑的解释。谢谢yurzui,终于明白你的意思了。它需要睡一夜。
<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
可由 Child(div
此处)及其自身(ng-template
此处)访问。
第二个 <div>
不是存在模板引用变量的 <div>
的兄弟。
更多解释here
该行为是预期的,因为 Child/Sibling 个元素可以引用模板引用变量。
如@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>
`,
})
正如 Tobias Bosch 所说
A variable declared inside of an *ngIf cannot be used outside of the *ngIf
https://github.com/angular/angular/issues/6179#issuecomment-233374700
Only the opposite way (i.e. declare a variable inside of *ngIf and use it outside of *ngIf) is not working, and won't work by design.
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 class 这样的可见性标志,而不是 *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
如果您使用的是 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)
}
}
在Angular9中,false
将是默认值。