Correct Way To Do Dom Manipulation In Angular 2+
TS
buttonColor : string = 'grey'changeColour() {
this.buttonColor = 'purple'
}
Angular also has a feature to allow event listener to be implemented only on a particular event
, e.g when enter key is pressed
, mouse clicked
or a combination of keys is pressed
.
Below is the snippet for our example:
HTML
<button (keyup.control.shift.enter)="changeColour()" [ngStyle]="{'background-color': buttonColor}">BUY NOW</button>
The colour
of the button becomes purple
when Ctrl+Shift+Enter
is pressed.
@HostListener and @HostBinding
:
This is similar to event binding
and property binding
in angular.
@HostBinding('value') val;
is same as [value]="val"
and
@HostListener('click') click(){ }
is same as (click)="click()"
.
@HostBinding
and @HostListener
are defined inside directive
whereas []
and ()
are defined inside the component template
.
Below is the snippet for our example:
HTML
<buttonclass="c_highlight">BUY NOW</button>
TS(host.directive.ts)
@Directive({
// Notice the . in selector => this directive will work for DOM with the c_highlight class selector: '.c_highlight'
})
exportclassHostDirective {
@HostBinding('style.backgroundColor') c_color = "red";
@HostListener('click') c_onclick() {
this.c_color = "purple" ;
}
}
Renderer2
:
This is basically a wrapper
over the browser API for DOM Manipulation
. The Renderer2 API can be run across platforms
other than the DOM and you can provide your own Renderer2 implementation
, unique to a platform. There are multiple DOM manipulation methods
present for the same like setStyle()
, createElement()
, createText()
, appendChild()
etc. and we can implement our own custom
methods too. This is similar to the template reference variable
in your example and we are using the reference
to the element to modify
its properties
.
Below is the snippet for our example:
HTML
<button (click) = "onClick()"#abcd>BUY NOW</button>
TS
@ViewChild('abcd')private abcd: ElementRef;
constructor(private renderer: Renderer2) {
}
onClick() {
this.renderer.setStyle(this.abcd.nativeElement, 'backgroundColor','purple');
}
Read More - https://angular.io/api/core/Renderer2
Template Reference Variable
:
This involves creating an id (reference)
for the element. This is similar to the jquery
approach wherein each element can have an id
and events can be defined on these elements by using the getElementById()
method. Example (as shown in your question):
HTML
<button (click)="changeColour()"id="buy-now">BUY NOW</button>
TS
changeColour() {
const b = <HTMLElement>document.querySelector('#buy-now');
b.style.backgroundColour = 'purple'
}
fromEvent()
from rxjs
:
This is similar to defining an Event Listener
on an element. The fromEvent
method creates an Observable
that emits events of a specific type coming from the given element. Only the reference
for the element has to be declared; the event is associated
with this reference. Example:
HTML
<button #abcd>BUY NOW</button>
TS
@ViewChild('abcd')private abcd: ElementRef;
ngOnInit(){
fromEvent(this.abcd.nativeElement, 'click').subscribe(res => this.abcd.nativeElement.style.backgroundColor = 'purple');
}
SUMMARY:
The choice for the technique used for DOM Manipulation
depends solely on the developer
. Each of these methods have their own benefits
and trade-offs
; like for Event Binding, performance
can be relatively slower when a large list is being modified as the change detection cycle
can only run again once this function returns. Method 1 and 2 are the best angular practices
as these avoid creating references
for elements which can be risky and can make your application more vulnerable
to XSS
attacks as pointed out by @Chellapan.
Solution 2:
According to Angular Documentation Using Element Ref is Vulnerable
Permitting direct access to the DOM can make your application more vulnerable to XSS attacks. Carefully review any use of ElementRef in your code. For more detail, see the Security Guide.
Use Renderer2 to manipulate the DOM.
Create a Template Ref in template and pass it to the changeColour method and Use renderer2 service which provide setStyle method to set the style of the element
component.html
<button #button (click)="changeColour(button)">BUY NOW</button>
component.ts
constructor(private renderer: Renderer2) { }
changeColour(element: HTMLElement) {
this.renderer.setStyle(element.nativeElement, 'backgroundColour ', 'purple');
}
Solution 3:
You can access the DOM element in the template with a template reference variable:
<button #btn (click)="btn.style.backgroundColor = 'purple'">BUY NOW</button>
Or you can pass the variable to a method:
<button #btn (click)="changeColor(btn)">BUY NOW</button>
and modify the element in code:
changeColour(element: HTMLElement) {
element.style.backgroundColour = 'purple';
}
See this stackblitz for a demo.
Post a Comment for "Correct Way To Do Dom Manipulation In Angular 2+"