Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to render a string from structural directive?

Tags:

angular

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.

like image 623
Lazar Ljubenović Avatar asked Nov 12 '20 18:11

Lazar Ljubenović


People also ask

Is * NGLF is a structural directive?

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.

What is * in structural directive?

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.

How do you use structural directives?

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.

Can we use two structural directive in a single HTML element?

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.


1 Answers

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.

like image 187
Aakash Garg Avatar answered Oct 20 '22 14:10

Aakash Garg