为什么在使用* ngIf时,角色模板局部变量在模板中不可用
使用* 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部分的工作版本: 第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',[]); } 我从这个问题中学到很多东西。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |