如何将模板引用变量与ngIf组合?

ada*_*ort 24 angular2-template angular

<div *ngIf="true" myHighlight #tRefVar="myHighlight"></div>
<div>tRefVar is {{tRefVar.foo}}</div>
Run Code Online (Sandbox Code Playgroud)

即使这*ngIf是真的,我也会得到一个Cannot read property 'foo' of undefined.如果我删除它*ngIf,它工作正常!

我尝试使用Elvis运算符tRefVar?.foo来解决错误,但之后它永远不会更新值.

https://plnkr.co/edit/5rsXygxK1sBbbkYdobjn?p=preview

我究竟做错了什么?

yur*_*zui 37

正如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>
Run Code Online (Sandbox Code Playgroud)

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);
      });
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这里没有嵌入式视图.一体化View_App_0.我们可以在这里看到我们的表达{{tRefVar?.foo}}

var currVal_1 = ((jit_nodeValue7(_v,2) == null)? null: jit_nodeValue7(_v,2).foo);
Run Code Online (Sandbox Code Playgroud)

它从索引为2的节点获取值

jit_directiveDef4(16384,
  [['tRefVar',4]],0,jit_HighlightDirective5,[jit_ElementRef6],null,null),(_l()(),
  jit_textDef2(null,['tRefVar is ','']))
Run Code Online (Sandbox Code Playgroud)

在同一视图中声明的

2)使用*ngIf

然后让我们按如下方式更改模板

<h2 *ngIf="true" myHighlight #tRefVar="myHighlight">tRefVar is {{tRefVar.foo}}</h2>
<div>tRefVar is {{tRefVar?.foo}}</div>
Run Code Online (Sandbox Code Playgroud)

输出如下

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);
      });
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

角创建嵌入视图View_App_1开以View_App_0.而我们的表达{{tRefVar?.foo}}已经变成了

var currVal_1 = ((_co.tRefVar == null)? null: _co.tRefVar.foo);
Run Code Online (Sandbox Code Playgroud)

它只是因为组件属性,因为没有节点将引用此模板变量View_App_0.它已经进入了嵌入式视图View_App_1

var currVal_0 = jit_nodeValue7(_v,1).foo;
Run Code Online (Sandbox Code Playgroud)

所以我们不能引用在嵌入视图之外的嵌入视图中声明的模板变量.

怎么解决?

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>
Run Code Online (Sandbox Code Playgroud)

3)使用,@ViewChild因为它将代表组件属性.或者使用@ViewChildren


Tom*_*yon 15

如果您使用的是 Angular 8,您可以通过添加视图子引用并将静态值设置为false.

示例模板代码:

<button type="button" (click)="eventsTable.someMethod()">Click Me!</button>
<div *ngIf="someValue" #eventsTable >
    SHIBAMBO!
</div>
Run Code Online (Sandbox Code Playgroud)

组件代码:

export class EventsComponent {
    @ViewChild('eventsTable', {static: false}) eventsTable: Table;

    constructor() {
        console.log(this.eventsTable)
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Angular 9 中,false将是默认值。