0

I want to write an Angular Directive, that takes in markdown (well text, to be markdown-ed...), renders and outputs it. (It will last also show/hide in relation to the language value specified, but that's not the problem here…).

  <div *xyz="EN">
    ## Englisch ENGLISCH The *quick brown* fox ENGLISCH jumps over the lazy dog. ENGLISCH The quick brown fox jumps ENGLISCH over the lazy dog. The quick brown fox jumps over the
    lazy dog. <strong class="foo" id="foo">Tag me now</strong>
  </div>

My problem is: I don't find access to the structural directives original contents. The templateRef contents (or badly worded .innerHTML).

view, template, el, viewChilden 1-3... above contents are nowhere to be found.

  @Directive({selector: '[xyz]'})
  export class MarkdownDirective implements OnInit, AfterViewInit, OnChanges {

    constructor(
      private view: ViewContainerRef,
      private template: TemplateRef<any>,
      private el: ElementRef,
      private renderer: Renderer2,
      private markdownService: MarkdownService
    ) {}

    @ViewChildren(MarkdownDirective) viewChildren!: QueryList<MarkdownDirective>;
    @ViewChildren(TemplateRef) viewChildren2!: QueryList<MarkdownDirective>;
    @ViewChildren('foo') viewChildren3!: QueryList<MarkdownDirective>;

    ngOnInit(): void {
      // anthing to do here?
    }

    ngAfterViewInit(): void {
      console.dir(this.view);
      console.dir(this.template);
      console.dir(this.el);
      console.dir(this.viewChildren);
      console.dir(this.viewChildren2);
      console.dir(this.viewChildren3);
    }

    ngOnChanges(): void {
      console.log('ngOnChanges()');
      console.dir(this.el.nativeElement);
      console.dir(this.template.elementRef.nativeElement);
    }
  }

Once I got that, my plan would be:

    1. const origTemplate: string = ...well, see above...
    1. const markdowned: string = this.markdownService.parse( origTemplate );
  • 3a. create new Template, or insert .innerHTML? (to force DOM buildup)
  • 3b. this.view.createComponent?
  • 3c. another view.... creating an EmbeddedView or a templateRef „from Scratch“?

The web is full of examples for structural directives in Angular. Sadly all I could find features to-show-or-not-to-show (reverting or inverting of *ngIf), not grabbing templateRef contents and doing more than simply reinserting...

this.view.createEmbeddedView(this.template).

Thinking about it, the builtIn *ngFor implementation might have what I need (since it does more than show-or-hide)... but I don't graps what they do how.

I consider ngAfterViewInit() to be the right moment, ngOnChanges() to be a dirty approach (flashes of content since already rendered, sneaking it into the DOM...). Am I wrong?

Unsure if this approach has something for me.

Frank N
  • 9,625
  • 4
  • 80
  • 110
  • I feel like the answer you are looking for is, you can, just use content children instead of view children, and of course listen to content init, not view init. – Munzer Aug 18 '22 at 16:02

1 Answers1

0
ngOnInit(): void {
  // anthing to do here?
}

Yes.

ngOnInit(): void {
    const embeddedViewRef = this.view.createEmbeddedView(this.template);
    const origTemplate = embeddedViewRef.rootNodes[0].innerHTML;
    const markdowned = this.markdownService.parse(origTemplate);
    embeddedViewRef.rootNodes[0].innerHTML = markdowned;
}

And that's it.

  1. When using a structural directive, unless the template is added to the view using createEmbeddedView you'll not find it anywhere.
  2. createEmbeddedView returns the ViewRef instance where you'll get all the template details.
  3. Setting innerHTML will work fine for a simple use case.
Ashish Dahiya
  • 650
  • 5
  • 14