为什么angular2模板局部变量使用时,无法在模板中使用的* ngIf [英] Why angular2 template local variables are not usable in templates when using *ngIf
问题描述
当引用该可以隐藏/销毁(因为* ngIf被使用并且一些元件被破坏)的输入,由主题标记语法#创建的本地变量(#TEST在下面的示例)angular2的不工作,甚至当元素在页面中存在。
When referencing an input that can be hidden/"destroyed" (because the *ngIf is used and some of the elements are destroyed), the local variable created by the hashtag syntax # (#test in the example below) of angular2 does not work, even when the element exists in the page.
在code是:
@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();
}
}
警报显示未定义,因为没有传递给函数。
The alert displays "undefined", because nothing is passed to that function.
是否有解决方案,使其工作?
我的目标是把重点将要创建的元素。
Is there a solution to make it work? My goal is to focus an element that will be created.
马克Rajcok给出解决方案:的使之与元素上使用elementRef和调用。重点()的afterViewInit指令
Solution given by Mark Rajcok: make a directive with an afterViewInit that uses elementRef and calls .focus() on the element.
有关的第1部分工作版本请参见本plunker:
<一href=\"http://plnkr.co/edit/JmBBHMo1hXLe4jrbpVdv?p=$p$pview\">http://plnkr.co/edit/JmBBHMo1hXLe4jrbpVdv?p=$p$pview
See this plunker for a working version of part 1: http://plnkr.co/edit/JmBBHMo1hXLe4jrbpVdv?p=preview
在的创建后的重点这个问题是固定的,我需要一种方法来重新聚焦()一个组成部分,就像test.focus()(其中#TEST是局部变量名称输入,但不能用这样的,因为我之前证明)。
Once this problem of "focus after creation" is fixed, I need a way to re-focus() a component, like in "test.focus()" (where #test is the local variable name for the input, but cannot be used like that as I demonstrated before).
马克Rajcok给出多解的
Multiple solutions given by Mark Rajcok
推荐答案
至于解决的重点问题,您可以创建一个属性指令, focusMe
:
As for a solution to the focus problem, you could create an attribute directive, 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 :添加为重新对焦功能的解决方案:
Update 1: Adding the solution for the re-focus feature:
import {Component, Directive, 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()
将焦点属性重置为假
将创建一个事件/在FocusDirective和输出特性发射()
事件时焦点()
被调用。然后AppComponent会听该事件并重置焦点属性。
An alternative to using setTimeout()
to reset the focus property to false
would be to create an event/output property on the FocusDirective, and emit()
an event when focus()
is called. The AppComponent would then listen for that event and reset the focus property.
更新2 :这是一种替代/更好的方式来添加重新对焦功能,使用ViewChild。我们不需要跟踪对焦状态就这样,我们也不需要对FocusMe指令的输入属性。
Update 2: Here's an alternative/better way to add the re-focus feature, using ViewChild. We don't need to track the focus state this way, nor do we need an input property on the FocusMe directive.
import {Component, Directive, ElementRef, 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用于访问子< A HREF =http://stackoverflow.com/a/34519344/215945>尖端):
Update 3: Here's yet another alternative that does not require a directive, which still uses ViewChild, but we access the child via a local template variable rather than an attribute directive (thanks @alexpods for 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 code使用NgZone,这样我们就不会引起角的变化检测算法后运行的setTimeout()
结束。 (更多变化检测,请参见这个答案)。
Update 4: I updated the code in Update 3 to use NgZone so that we don't cause Angular's change detection algorithm to run after the setTimeout()
finishes. (For more on change detection, see this answer).
更新5 :我更新了code在上面plunker使用渲染,使其网络工作者的安全。访问焦点()
直接在 nativeElement
气馁。
Update 5: I updated the code in the above plunker to use Renderer to make it web worker safe. Accessing focus()
directly on nativeElement
is discouraged.
focusInput1() {
this._renderer.invokeElementMethod(
this.input1ElementRef.nativeElement, 'focus', []);
}
从我这个问题,学到了很多东西。
I learned a lot from this question.
这篇关于为什么angular2模板局部变量使用时,无法在模板中使用的* ngIf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!