Does anybody know how to get hold of an element defined in a component template? Polymer makes it really easy with the $
and $$
.
I was just
Note: This doesn't apply to Angular 6 and above as ElementRef
became ElementRef<T>
with T
denoting the type of nativeElement
.
I would like to add that if you are using ElementRef
, as recommended by all answers, then you will immediately encounter the problem that ElementRef
has an awful type declaration that looks like
export declare class ElementRef {
nativeElement: any;
}
this is stupid in a browser environment where nativeElement is an HTMLElement
.
To workaround this you can use the following technique
import {Inject, ElementRef as ErrorProneElementRef} from '@angular/core';
interface ElementRef {
nativeElement: HTMLElement;
}
@Component({...}) export class MyComponent {
constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}
import { Component, ElementRef, ViewChild} from '@angular/core';
@Component({
selector: 'my-app',
template:
`
<input #inputEl value="hithere">
`,
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
@ViewChild('inputEl') inputEl:ElementRef;
ngAfterViewInit() {
console.log(this.inputEl);
}
}
#inputEl
on the <input>
tag.ngAfterViewInit
lifecycle hook.Note:
If you want to manipulate the DOM elements use the Renderer2 API instead of accessing the elements directly. Permitting direct access to the DOM can make your application more vulnerable to XSS attacks
to get the immediate next sibling ,use this
event.source._elementRef.nativeElement.nextElementSibling
Selecting target element from the list. It is easy to select particular element from the list of same elements.
component code:
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= '';
}
}
}
html code:
<ul *ngFor="let event of listEvents; let i = index">
<li (click)="selectElement(event.name, i)" [class]="event.class">
{{ event.name }}
</li>
css code:
.selected {
color: red;
background:blue;
}
Instead of injecting ElementRef
and using querySelector
or similar from there, a declarative way can be used instead to access elements in the view directly:
<input #myname>
@ViewChild('myname') input;
element
ngAfterViewInit() {
console.log(this.input.nativeElement.value);
}
StackBlitz example
@ViewChildren('var1,var2,var3')
). <ng-content>
projected elements).descendants
@ContentChildren()
is the only one that allows to also query for descendants
@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField;
{descendants: true}
should be the default but is not in 2.0.0 final and it's considered a bug
This was fixed in 2.0.1
read
If there are a component and directives the read
parameter allows to specify which instance should be returned.
For example ViewContainerRef
that is required by dynamically created components instead of the default ElementRef
@ViewChild('myname', { read: ViewContainerRef }) target;
subscribe changes
Even though view children are only set when ngAfterViewInit()
is called and content children are only set when ngAfterContentInit()
is called, if you want to subscribe to changes of the query result, it should be done in 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));
}
direct DOM access
can only query DOM elements, but not components or directive instances:
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);
}
}
get arbitrary projected content
See Access transcluded content
You can get a handle to the DOM element via ElementRef
by injecting it into your component's constructor:
constructor(private myElement: ElementRef) { ... }
Docs: https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html