How to conditionally insert/remove host DOM element in angular 2 directive
Solution 1
This implementation will be similar to what ngIf directive is. And the Angular guide for structural directives (which you plan to create too) gives an example of myUnless
that just reverses ngIf
.
You implementation for access will look similar to the myUnless
implementation.
@Directive({ selector: '[access]' })
export class AccessDirective {
constructor(
private _templateRef: TemplateRef,
private _viewContainer: ViewContainerRef
) { }
@Input() set myUnless(condition: boolean) {
if (condition) {
this._viewContainer.createEmbeddedView(this._templateRef);
} else {
this._viewContainer.clear();
}
}
}
And use it like:
<li *access="isAdmin"><a>admin-only link</a></li>
Solution 2
Removing an element from the DOM is done with the *ngIf
directive.
But if you really insist on using your own directive, I believe ElementRef is the way to go. Even though I would not advice on using this
You will get something like this:
import {Directive} from 'angular2/angular2';
@Directive({
selector: '[access]' //this is how you address an attribute directive
})
export class Access {
constructor(private _userService : UserService, private _elementRef : ElementRef) {}
ngOnInit() {
this._checkAdmin();
}
private _checkAdmin() : void {
if(!this._userService.currentUser.hasRole('admin')) {
let el : HTMLElement = this._elementRef.nativeElement;
el.parentNode.removeChild(el);
}
}
}
dKab
Updated on July 20, 2022Comments
-
dKab over 1 year
I want to create a directive that will decide whether should or should not its host element apppear on the page. Ideally I would like it to remove the element from the DOM and not just hide/show it with css. Usecase is:
<ul role="navigation"> <li><a>public link</a></li> <li><a>public link2</a></li> <li access="admin"><a>admin-only link</a></li> </ul>
It would use UserService to get currentUser roles and if there's no admin there the
li
would be removed.I suppose I could achieve the same effect with
ng-if
(if it's still available in angular 2) by passing the expression to evaulate in the main component. But with the directive it is more semantic and elegant.Is it possible?
import {Directive} from 'angular2/angular2'; @Directive({ selector: 'access' }) export class Access { //what goes here }
I could've easily done that in angular 1 (inside directive's
compile
function), but how can I do this in Angular 2? -
dKab over 8 yearswhy do you advise not to do this?
-
Poul Kruijt over 8 yearsbecause, in such a simple thing as this,
*ngIf
is way more intuitive, and leaves the DOM editing to angular -
dKab over 8 yearsI need to access value of the
access
attribute but in the constuructor it is not yet available - it'sundefined
-
Poul Kruijt over 8 yearsI've edit my answer. I believe you have to use the ngOnInit function. This is called after the constructor and after attribute binding has finished
-
Mark Rajcok over 8 yearsThe Attribute Directive guide warns against direct DOM manipulation, e.g., use of
removeChild()
: "Manipulating the DOM directly is a practice we'd rather avoid because it chains us to the browser DOM API... The rendering phase could be offloaded to a Web Worker for faster performance. Our directive might work when we ran the application outside the browser, perhaps on the server in a pre-render phase." -
Glenn Bullock almost 7 yearsHad this same question and found this in the angular docs. angular.io/docs/ts/latest/guide/structural-directives.html