angular - reactivos - ¿Cómo puedo seleccionar un elemento en una plantilla de componente?
tablas angular 4 (10)
En lugar de inyectar
ElementRef
y usar
querySelector
o similar desde allí, se puede usar una forma declarativa para acceder a los elementos en la vista directamente:
<input #myname>
@ViewChild(''myname'') input;
elemento
ngAfterViewInit() {
console.log(this.input.nativeElement.value);
}
- @ViewChild() admite la directiva o el tipo de componente como parámetro, o el nombre (cadena) de una variable de plantilla.
-
@ViewChildren()
también admite una lista de nombres como lista separada por comas (actualmente no se permiten espacios
@ViewChildren(''var1,var2,var3'')
). -
@ContentChild()
y
@ContentChildren()
hacen lo mismo pero a la luz DOM (elementos proyectados
<ng-content>
).
descendientes
@ContentChildren()
es el único que permite consultar también descendientes
@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField;
{descendants: true}
debería ser el valor predeterminado, pero no está en 2.0.0 final y se
considera un error
Esto se solucionó en 2.0.1
leer
Si hay un componente y directivas, el parámetro de
read
permite especificar qué instancia se debe devolver.
Por ejemplo,
ViewContainerRef
que requieren los componentes creados dinámicamente en lugar del elemento predeterminado
ElementRef
@ViewChild(''myname'', { read: ViewContainerRef }) target;
suscribir cambios
Aunque los elementos
ngAfterViewInit()
vista solo se establecen cuando se llama a
ngAfterViewInit()
y los elementos
ngAfterViewInit()
contenido solo se establecen cuando se llama a
ngAfterContentInit()
, si desea suscribirse a los cambios del resultado de la consulta, debe hacerlo en
ngOnInit()
https://github.com/angular/angular/issues/9689#issuecomment-229247134
@ViewChildren(SomeType) viewChildren;
@ContentChildren(SomeType) contentChildren;
ngOnInit() {
this.viewChildren.changes.subscribe(changes => console.log(changes));
this.contentChildren.changes.subscribe(changes => console.log(changes));
}
acceso DOM directo
solo puede consultar elementos DOM, pero no componentes o instancias de directivas:
export class MyComponent {
constructor(private elRef:ElementRef) {}
ngAfterViewInit() {
var div = this.elRef.nativeElement.querySelector(''div'');
console.log(div);
}
// for transcluded content
ngAfterContentInit() {
var div = this.elRef.nativeElement.querySelector(''div'');
console.log(div);
}
}
obtener contenido proyectado arbitrario
¿Alguien sabe cómo hacerse con un elemento definido en una plantilla de componente?
Polymer lo hace realmente fácil con
$
y
$$
.
Me preguntaba cómo hacerlo en Angular.
Tome el ejemplo del tutorial:
import {Component} from ''@angular/core''
@Component({
selector:''display''
template:`
<input #myname(input)="updateName(myname.value)"/>
<p>My name : {{myName}}</p>
`
})
export class DisplayComponent {
myName: string = "Aman";
updateName(input: String) {
this.myName = input;
}
}
¿Cómo puedo obtener una referencia del elemento
p
o
input
desde la definición de clase?
Para las personas que intentan tomar la instancia del componente dentro de
*ngIf
o
*ngSwitchCase
, pueden seguir este truco.
Crea una directiva
init
.
import {
Directive,
EventEmitter,
Output,
OnInit,
ElementRef
} from ''@angular/core'';
@Directive({
selector: ''[init]''
})
export class InitDirective implements OnInit {
constructor(private ref: ElementRef) {}
@Output() init: EventEmitter<ElementRef> = new EventEmitter<ElementRef>();
ngOnInit() {
this.init.emit(this.ref);
}
}
Exporte su componente con un nombre como
myComponent
@Component({
selector: ''wm-my-component'',
templateUrl: ''my-component.component.html'',
styleUrls: [''my-component.component.css''],
exportAs: ''myComponent''
})
export class MyComponent { ... }
Use esta plantilla para obtener la instancia de
ElementRef
AND
MyComponent
<div [ngSwitch]="type">
<wm-my-component
#myComponent="myComponent"
*ngSwitchCase="Type.MyType"
(init)="init($event, myComponent)">
</wm-my-component>
</div>
Use este código en TypeScript
init(myComponentRef: ElementRef, myComponent: MyComponent) {
}
Puede obtener un identificador para el elemento DOM a través de
ElementRef
inyectándolo en el constructor de su componente:
constructor(myElement: ElementRef) { ... }
Documentos: https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html
Selección del elemento objetivo de la lista. Es fácil seleccionar un elemento particular de la lista de los mismos elementos.
código de componente:
export class AppComponent {
title = ''app'';
listEvents = [
{''name'':''item1'', ''class'': ''''}, {''name'':''item2'', ''class'': ''''},
{''name'':''item3'', ''class'': ''''}, {''name'':''item4'', ''class'': ''''}
];
selectElement(item: string, value: number) {
console.log("item="+item+" value="+value);
if(this.listEvents[value].class == "") {
this.listEvents[value].class=''selected'';
} else {
this.listEvents[value].class= '''';
}
}
}
código HTML:
<ul *ngFor="let event of listEvents; let i = index">
<li (click)="selectElement(event.name, i)" [class]="event.class">
{{ event.name }}
</li>
código css:
.selected {
color: red;
background:blue;
}
importe el decorador
ViewChild
desde
@angular/core
, así:
Código HTML:
<form #f="ngForm">
...
...
</form>
Código TS:
import { ViewChild } from ''@angular/core'';
class TemplateFormComponent {
@ViewChild(''f'') myForm: any;
.
.
.
}
ahora puede usar el objeto ''myForm'' para acceder a cualquier elemento dentro de él en la clase.
para obtener el próximo hermano inmediato, use esto
event.source._elementRef.nativeElement.nextElementSibling
Nota
: Esto no se aplica a Angular 6 y superior, ya que
ElementRef
convirtió en
ElementRef<T>
con
T
denota el tipo de
nativeElement
.
Me gustaría agregar que si está usando
ElementRef
, como lo recomiendan todas las respuestas, inmediatamente se encontrará con el problema de que
ElementRef
tiene una declaración de tipo horrible que se parece a
export declare class ElementRef {
nativeElement: any;
}
Esto es estúpido en un entorno de navegador donde nativeElement es un elemento
HTMLElement
.
Para solucionar esto, puede usar la siguiente técnica
import {Inject, ElementRef as ErrorProneElementRef} from ''@angular/core'';
interface ElementRef {
nativeElement: HTMLElement;
}
@Component({...}) export class MyComponent {
constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}
Angular 4+
: use
renderer.selectRootElement
con un selector CSS para acceder al elemento.
Tengo un formulario que inicialmente muestra una entrada de correo electrónico. Después de ingresar el correo electrónico, el formulario se ampliará para permitirles continuar agregando información relacionada con su proyecto. Sin embargo, si no son un cliente existente, el formulario incluirá una sección de dirección sobre la sección de información del proyecto.
A partir de ahora, la parte de entrada de datos no se ha dividido en componentes, por lo que las secciones se administran con directivas * ngIf. Necesito poner el foco en el campo de notas del proyecto si son clientes existentes, o en el campo de nombre si son nuevos.
Probé las soluciones sin éxito. Sin embargo, la Actualización 3 en this respuesta me dio la mitad de la solución final. La otra mitad provino de la respuesta de MatteoNY en this hilo. El resultado es este:
import { NgZone, Renderer } from ''@angular/core'';
constructor(private ngZone: NgZone, private renderer: Renderer) {}
setFocus(selector: string): void {
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
this.renderer.selectRootElement(selector).focus();
}, 0);
});
}
submitEmail(email: string): void {
// Verify existence of customer
...
if (this.newCustomer) {
this.setFocus(''#firstname'');
} else {
this.setFocus(''#description'');
}
}
Dado que lo único que estoy haciendo es establecer el foco en un elemento, no necesito preocuparme por la detección de cambios, por lo que puedo ejecutar la llamada a
renderer.selectRootElement
fuera de Angular.
Debido a que necesito dar tiempo a las nuevas secciones para que se procesen, la sección del elemento se ajusta en un tiempo de espera para permitir que los subprocesos de procesamiento se pongan al día antes de que se intente la selección del elemento.
Una vez que todo está configurado, simplemente puedo llamar al elemento usando selectores básicos de CSS.
Sé que este ejemplo se ocupó principalmente del evento de enfoque, pero es difícil para mí que esto no pueda usarse en otros contextos.
import { Component, ElementRef, OnInit } from ''@angular/core'';
@Component({
selector:''display'',
template:`
<input (input)="updateName($event.target.value)">
<p> My name : {{ myName }}</p>
`
})
class DisplayComponent implements OnInit {
constructor(public element: ElementRef) {
this.element.nativeElement // <- your direct element reference
}
ngOnInit() {
var el = this.element.nativeElement;
console.log(el);
}
updateName(value) {
// ...
}
}
Ejemplo actualizado para trabajar con la última versión
Para más detalles sobre el elemento nativo, here
*/
import {Component,ViewChild} from ''@angular/core'' /*Import View Child*/
@Component({
selector:''display''
template:`
<input #myname (input) = "updateName(myname.value)"/>
<p> My name : {{myName}}</p>
`
})
export class DisplayComponent{
@ViewChild(''myname'')inputTxt:ElementRef; /*create a view child*/
myName: string;
updateName: Function;
constructor(){
this.myName = "Aman";
this.updateName = function(input: String){
this.inputTxt.nativeElement.value=this.myName;
/*assign to it the value*/
};
}
}