reactivos - pasar parametros entre componentes angular 4
¿Por qué las variables locales de la plantilla angular2 no se pueden usar en las plantillas cuando se usa*ngIf? (1)
En cuanto a una solución al problema de enfoque, puede crear una directiva de atributos, 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;
}
}
Actualización 1 : Agregar la solución para la función de reenfoque:
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);
}
}
Una alternativa al uso de setTimeout()
para restablecer la propiedad de foco a false
sería crear una propiedad de evento / salida en FocusDirective, y emit()
un evento cuando se llama a focus()
. El AppComponent entonces escucharía ese evento y restablecería la propiedad de enfoque.
Actualización 2 : Aquí hay una forma alternativa / mejor de agregar la función de reenfoque, usando ViewChild. No necesitamos rastrear el estado de enfoque de esta manera, ni necesitamos una propiedad de entrada en la directiva FocusMe.
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();
}
}
Actualización 3 : Aquí hay otra alternativa que no requiere una directiva, que aún usa ViewChild, pero accedemos al niño a través de una variable de plantilla local en lugar de una directiva de atributos (gracias a @alexpods por la sugerencia ):
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);
}
}
Actualización 4 : Actualicé el código en la Actualización 3 para usar NgZone para que no cause que el algoritmo de detección de cambios de Angular se ejecute después de que setTimeout()
. (Para más información sobre la detección de cambios, vea esta respuesta ).
Actualización 5 : Actualicé el código en el plunker anterior para usar Renderer para que sea seguro para el trabajador web. nativeElement
se nativeElement
acceder a focus()
directamente en nativeElement
.
focusInput1() {
this._renderer.invokeElementMethod(
this.input1ElementRef.nativeElement, ''focus'', []);
}
Aprendí mucho de esta pregunta.
La parte 1 "#test" no está definida cuando se usa * ngIf
Al hacer referencia a una entrada que puede ocultarse / "destruirse" (porque se usa * ngIf y algunos de los elementos se destruyen), la variable local creada por la sintaxis hashtag # (#test en el ejemplo a continuación) de angular2 no funciona , incluso cuando el elemento existe en la página.
El código era:
@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();
}
}
La alerta muestra "indefinido", porque no se pasa nada a esa función.
¿Hay una solución para que funcione? Mi objetivo es enfocar un elemento que será creado.
Solución dada por Mark Rajcok: haga una directiva con afterViewInit que use elementRef y llame a .focus () en el elemento.
Ver este plunker para una versión de trabajo de la parte 1: http://plnkr.co/edit/JmBBHMo1hXLe4jrbpVdv?p=preview
Parte 2: cómo reenfocar ese elemento después de la creación inicial
Una vez que se solucione este problema de "enfoque después de la creación", necesito una manera de volver a enfocar () un componente, como en "test.focus ()" (donde #test es el nombre de la variable local para la entrada, pero no puede ser utilizado así como lo demostré antes).
Múltiples soluciones dadas por Mark Rajcok