ViewContainerRef
offers methods createEmbeddedView
(which accepts TemplateRef
, for rendering templates) and createComponent
(which accepts ComponentFactory
, for rendering components). But what about a simple string?
The only workaround I see is to have a DummyComponent
and then feed a document.createTextNode('string')
to projectableNodes
.
@Component({ template: `<ng-content></ng-content>` }) class DummyComponent {}
const dummyComponentFactory = this.cfr.resoveComponentFactory(DummyComponent)
const nodes = [[document.createTextNode('string')]]
this.viewContainerRef.createComponent(dummyComponentFactory, 0, injector, nodes)
But this is just abusing the API and has an enormous overhead for rendering a simple string.
Structural directives are directives which change the DOM layout by adding and removing DOM elements. Angular provides a set of built-in structural directives (such as NgIf , NgForOf , NgSwitch and others) which are commonly used in all Angular projects.
Structural directives are responsible for the Structure and Layout of the DOM Element. It is used to hide or display the things on the DOM. Structural Directives can be easily identified using the '*'. Every Structural Directive is preceded by a '*' symbol.
These directives work by using the HTML 5 <ng-template> tag. This is a new tag in HTML which is specifically designed to hold template code. It can sit under the body element but any content inside it is not shown in the browser. This is the NgFor directive itself.
Comparing Component and Structural Directives A component directive can be created multiple times, that is, every component in Angular will have a @Component decorator attached, while we cannot apply more than one structural directive to the same HTML element.
If you really want to achieve it via directive, its possible. Please refer to directive code below :-
import {
Directive,
Input,
NgIterable,
OnChanges,
OnInit,
Renderer2,
TemplateRef,
ViewContainerRef
} from "@angular/core";
@Directive({
selector: "[ngJoin]"
})
export class NgJoinDirective<T, U extends NgIterable<T> = NgIterable<T>>
implements OnInit, OnChanges {
@Input() ngJoinOf: any[];
@Input() ngJoinSeparator: string = ",";
constructor(
private _viewContainer: ViewContainerRef,
private _template: TemplateRef<any>,
private renderer2: Renderer2
) {}
ngOnChanges() {
this.createText();
}
ngOnInit() {
this.createText();
}
createText() {
if (this.ngJoinOf) {
this._viewContainer.clear();
console.log(this.ngJoinOf);
const container = this._template.createEmbeddedView({});
const parentNode = container.rootNodes[0];
const textNode = this.renderer2.createText(
this.ngJoinOf.join(this.ngJoinSeparator)
);
this.renderer2.insertBefore(parentNode, textNode, parentNode.firstChild);
this._viewContainer.insert(container);
}
}
}
and used in html like below :-
<p *ngJoin="let item of arr;separator: '/'">
if you will not give separator it will take , as default separator.
Working Stackblitz :-
https://stackblitz.com/edit/angular-rumkzc?file=src/app/app.component.html
If you are just looking to print array via join in template using a separator, pipe will be a ideal choice instead of directive. Such a pipe is provided by a library.
https://github.com/fknop/angular-pipes
The pipe name is join.
Note :- I have not handled, any edge cases, you might want to handle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With