Reputation: 27556
I'd like to create a structural directive which behaves as follows:
<p *myDirective="condition">This is some text</p>
condition
is false
then the <p>
tag is not rendered at all.condition
is true
then the <p>
tag is rendered with an extra class
attribute.So, either there's nothing rendered, or:
<p class="my-added-class">This is some text</p>
In other words, it's a bit like *ngIf
, but with additional behaviour.
I can find examples of how to do the include/exclude behaviour (in fact there is such an example in the Angular docs). I can also find examples of how to add a class to an element using the Renderer2
API.
However, I don't see how I can combine these techniques, because the first method manipulates the viewContainer
to create an embedded view, whereas the second method uses the renderer to manipulate an element.
Is there a way to do this? Can I somehow create the embedded view and then manipulate the elements it creates? Or can I manipulate the template to change how the view is rendered?
[NOTE: @HostBinding
does not work with structural directives, so that's not an option]
Upvotes: 5
Views: 2626
Reputation: 32806
An other way
just to play around :)
Using Renderer2 is universal safe
import {
Directive,
Renderer2,
TemplateRef,
ViewContainerRef,
ElementRef,
Input, OnInit } from '@angular/core';
@Directive({
selector: '[appMy]'
})
export class MyDirective implements OnInit{
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private renderer: Renderer2) { }
@Input() set appMy(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
ngOnInit() {
const elementRef = this.viewContainer.get(0).rootNodes[0] as ElementRef;
this.renderer.addClass(elementRef, 'myclass');
}
}
Following the @Pankaj way but with renderer
@Input() set appMy(condition: boolean) {
if (condition) {
const view = this.viewContainer.createEmbeddedView(this.templateRef);
this.renderer.addClass(view.rootNodes[0], 'myclass');
} else {
this.viewContainer.clear();
}
}
Upvotes: 3
Reputation: 136184
I'd think of adding class on the DOM when it satisfied the expression passed to it (inside setter). You can grab the ElementRef
dependency inside directive and append a class
to it which its truthy.
@Input() set myDirective(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.elementRef.nativeElement.nextElementSibling.classList.add('my-added-class'); // renderer API can be used here
// as Alex and Yurzui suggested
// const view = this.viewContainer.createEmbeddedView(this.templateRef);
// view.rootNodes[0].classList.add('some-class')
} else if (condition) {
this.viewContainer.clear();
}
}
Upvotes: 3