DEV Community

Michael Muscat
Michael Muscat

Posted on • Edited on

Turn a Directive Into a Fragment

You probably shouldn't do this. It's a bad idea. So anyway here's the code.

@Directive()
export class Fragment {
  nativeElement;
  comment;
  childNodes

  constructor() {
    this.nativeElement = inject(ElementRef).nativeElement;
    this.comment = document.createComment(
      ` ${Object.getPrototypeOf(this).constructor.name} `
    );
  }

  ngAfterViewInit() {
    const { nativeElement, comment } = this;
    const parent = nativeElement.parentElement;
    this.childNodes = Array.from(nativeElement.childNodes)
    parent.insertBefore(comment, nativeElement);
    for (const node of this.childNodes) {
      parent.insertBefore(node, nativeElement);
    }
    nativeElement.remove();
  }

  ngOnDestroy() {
    this.comment.remove();
    for (const node of this.childNodes) {
      node.remove()
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This will replace the host element of a directive with whatever is inside it. It even leaves a nice little comment behind.

To see how it's used let's create a provider that will pass through values from the template.

@Directive({
  selector: 'MyProvider',
})
export class MyProvider extends Fragment {
  @Input() value;
}
Enter fullscreen mode Exit fullscreen mode

We're using TitleCase here to distinguish it from rendered DOM elements. Remember that Angular selectors are case sensitive.

Now we can import the directive and use it in a template.

<MyProvider [value]="name">
  <hello></hello>
</MyProvider>
Enter fullscreen mode Exit fullscreen mode

The hello component can then inject the provider to read its value.

@Component({
  selector: 'hello',
  template: `<h1>Hello {{provider.value}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`],
})
export class HelloComponent {
  provider = inject(MyProvider);
}
Enter fullscreen mode Exit fullscreen mode

See it in action on StackBlitz

When we look at the DOM we can see that the host element is replaced with a HTML comment.

Image description

Is This a Good Idea?

Probably not. All it does is add some sugar to <ng-container> in a not-very efficient way. There are probably other side effects I'm not aware of.

Can you think of a use case?

AWS Q Developer image

Your AI Code Assistant

Ask anything about your entire project, code and get answers and even architecture diagrams. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Start free in your IDE

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay