使用* ngIf时,第1部分“#test”未定义

当引用可以隐藏/“销毁”的输入(因为使用了* ngIf并且某些元素被销毁),由angular2的主题标签语法#(#test在下面的示例中)创建的局部变量不起作用,即使元素存在于页面中。

代码是:

@Component({
    selector: 'my-app',template: `<h1>My First Angular 2 App</h1>
    <button (click)="focusOther(test)">test</button>
    <input #test *ngIf="boolValue" >
    `
})
export class AppComponent { 

  private isVisible = false;

  focusOther(testElement){
    this.isVisible = true;
    alert(testElement);
    testElement.focus();
  }

}

警报显示“undefined”,因为没有任何内容被传递给该功能。

是否有解决方案使其工作?
我的目标是集中一个将被创建的元素。

Mark Rajcok提供的解决方案:使用一个使用elementRef并在元素上调用.focus()的afterViewInit指令。

看到这个plunker的第1部分的工作版本:
http://plnkr.co/edit/JmBBHMo1hXLe4jrbpVdv?p=preview

第2部分如何在初始创建后重新聚焦该元素

一旦这个“创建后聚焦”的问题被修复,我需要一种方法来重新聚焦()一个组件,如“test.focus()”(其中#test是输入的局部变量名,但不能像以前演示过的那样使用)。

Mark Rajcok提供了多种解决方案

对于焦点问题的解决方案,您可以创建一个属性指令focusMe:
import {Component,Directive,ElementRef} from 'angular2/core';
@Directive({
  selector: '[focusMe]'
})
export class FocusDirective {
  constructor(private el: ElementRef) {}
  ngAfterViewInit() {
    this.el.nativeElement.focus();
  }
}
@Component({
    selector: 'my-app',directives: [FocusDirective],template: `<h1>My First Angular 2 App</h1>
      <button (click)="toggle()">toggle</button>
      <input focusMe *ngIf="isVisible">
    `
})
export class AppComponent { 
  constructor() { console.clear(); }
  private isVisible = false;
  toggle() {
    this.isVisible = !this.isVisible;
  }
}

Plunker

更新1:添加重新聚焦功能的解决方案:

import {Component,ElementRef,Input} from 'angular2/core';

@Directive({
  selector: '[focusMe]'
})
export class FocusMe {
    @Input('focusMe') hasFocus: boolean;
    constructor(private elementRef: ElementRef) {}
    ngAfterViewInit() {
      this.elementRef.nativeElement.focus();
    }
    ngOnChanges(changes) {
      //console.log(changes);
      if(changes.hasFocus && changes.hasFocus.currentValue === true) {
        this.elementRef.nativeElement.focus();
      }
    }
}
@Component({
    selector: 'my-app',template: `<h1>My First Angular 2 App</h1>
    <button (click)="showinput()">Make it visible</button>
    <input *ngIf="inputIsVisible" [focusMe]="inputHasFocus">
    <button (click)="focusinput()" *ngIf="inputIsVisible">Focus it</button>
    `,directives:[FocusMe]
})
export class AppComponent {
  private inputIsVisible = false;
  private inputHasFocus = false;
  constructor() { console.clear(); }
  showinput() {
    this.inputIsVisible = true;
  }
  focusinput() {
    this.inputHasFocus = true;
    setTimeout(() => this.inputHasFocus = false,50);
  }
}

Plunker

使用setTimeout()将focus属性重置为false的替代方法是在FocusDirective上创建一个事件/输出属性,并在调用focus()时发出一个事件。然后AppComponent将监听该事件并重置focus属性。

更新2:这是使用ViewChild添加重点焦点功能的替代/更好的方式。我们不需要以这种方式跟踪焦点状态,也不需要在FocusMe指令上输入属性。

import {Component,Input,ViewChild} from 'angular2/core';

@Directive({
  selector: '[focusMe]'
})
export class FocusMe {
    constructor(private elementRef: ElementRef) {}
    ngAfterViewInit() {
      // set focus when element first appears
      this.setFocus();
    }
    setFocus() {
      this.elementRef.nativeElement.focus();
    }
}
@Component({
    selector: 'my-app',template: `<h1>My First Angular 2 App</h1>
    <button (click)="showinput()">Make it visible</button>
    <input *ngIf="inputIsVisible" focusMe>
    <button (click)="focusinput()" *ngIf="inputIsVisible">Focus it</button>
    `,directives:[FocusMe]
})
export class AppComponent {
  @ViewChild(FocusMe) child;
  private inputIsVisible = false;
  constructor() { console.clear(); }
  showinput() {
    this.inputIsVisible = true;
  }
  focusinput() {
    this.child.setFocus();
  }
}

Plunker

更新3:这是另一个不需要使用ViewChild的指令的替代方法,但是我们通过一个本地模板变量而不是一个属性指令来访问该子进程(感谢@alexpods为the tip):

import {Component,ViewChild,ngzone} from 'angular2/core';

@Component({
    selector: 'my-app',template: `<h1>Focus test</h1>
    <button (click)="showinput()">Make it visible</button>
    <input #input1 *ngIf="input1IsVisible">
    <button (click)="focusInput1()" *ngIf="input1IsVisible">Focus it</button>
    `,})
export class AppComponent {
  @ViewChild('input1') input1ElementRef;
  private input1IsVisible = false;
  constructor(private _ngzone: ngzone) { console.clear(); }
  showinput() {
    this.input1IsVisible = true;
    // Give ngIf a chance to render the <input>.
    // Then set the focus,but do this outside the Angualar zone to be efficient.
    // There is no need to run change detection after setTimeout() runs,// since we're only focusing an element.
    this._ngzone.runOutsideAngular(() => { 
      setTimeout(() => this.focusInput1(),0);
   });
  }
  setFocus(elementRef) {
    elementRef.nativeElement.focus();
  }
  ngDoCheck() {
    // if you remove the ngzone stuff above,you'll see
    // this log 3 times instead of 1 when you click the
    // "Make it visible" button.
    console.log('doCheck');
  }
  focusInput1() {
    this.setFocus(this.input1ElementRef);
  }
}

Plunker

更新4:我更新了更新3中的代码以使用ngzone,以便在setTimeout()完成后,我们不会导致Angular的更改检测算法运行。 (有关更改检测的更多信息,请参阅this answer)。

更新5:我更新了上面的代码,使用Renderer来使web worker安全。不要直接在nativeElement上访问focus()。

focusInput1() {
  this._renderer.invokeElementMethod(
    this.input1ElementRef.nativeElement,'focus',[]);
}

我从这个问题中学到很多东西。

为什么在使用* ngIf时,角色模板局部变量在模板中不可用的更多相关文章

  1. HTML5 input新增type属性color颜色拾取器的实例代码

    type 属性规定 input 元素的类型。本文较详细的给大家介绍了HTML5 input新增type属性color颜色拾取器的实例代码,感兴趣的朋友跟随脚本之家小编一起看看吧

  2. amazeui模态框弹出后立马消失并刷新页面

    这篇文章主要介绍了amazeui模态框弹出后立马消失并刷新页面,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. 移动HTML5前端框架—MUI的使用

    这篇文章主要介绍了移动HTML5前端框架—MUI的使用的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. AmazeUI 模态窗口的实现代码

    这篇文章主要介绍了AmazeUI 模态窗口的实现代码,代码简单易懂,非常不错,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. ios – UIPopoverController出现在错误的位置

    所以我花了一些时间寻找答案,但到目前为止还没有找到任何答案.我正在尝试从UIInputAccessoryView上的按钮呈现弹出窗口.UIBarButtonItem我想显示popover来自定制视图,所以我可以使用图像.我创建这样的按钮:当需要显示popover时,我这样做:但我得到的是:弹出窗口看起来很好,但它应该出现在第一个按钮上时出现在第二个按钮上.然后我发现了这个问题:UIBarButto

  6. ios – 关闭UIBarButtonItem上的突出显示

    我正在尝试使用UIBarButtonItem在我的UIToolbar上添加标题.我使用简单的风格,看起来很好,但我似乎无法让它停止突出显示触摸.“突出显示时触摸”选项不适用于条形按钮项目.有没有快速简便的方法来做到这一点?

  7. 以编程方式调整iOS中的按钮大小

    我正在使用XCode4.6.1并开发iOS6.我在故事板上添加了一个按钮.我在我的实现文件ViewController.m中创建了一个插座:我尝试按如下所示更改按钮b1的属性(在同一个文件中:ViewController.m):当我在模拟器中运行应用程序时,按钮的alpha成功设置为0.5.但是,按钮的位置和大小不会改变.我尝试了各种方法来实现它.然而似乎没有任何作用.我想知道我做错了什么.我对O

  8. 如何在iOS / Swift的顶部导航栏中添加“继续”按钮

    我想在导航栏的右侧添加一个“继续”按钮.如何实现这一目标?我一直在尝试使用UIBarButtonItem上的一些方法,但无法使其正常工作.我迄今为止的最大努力是:但我在第一行遇到错误.它不喜欢“style”参数.我也试过了但没有运气.仍然停留在样式参数上.有任何想法吗?

  9. ios – 将图像添加到界面构建器中的按钮

    我想在我的按钮而不是文本中添加图像.我可以在界面构建器中这样做吗?我可以看一下这个例子吗?

  10. ios – 自定义BackBarButtonItem

    主要原因是您丢失了标准后退按钮滑动动画以更改视图.此外,这意味着我不需要使用自定义按钮或编写自定义方法返回.它只是起作用.希望这也能解决别人的问题,我知道我已经坚持了3个小时!

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部