angularangular7angular2-directivesangular-renderer2

Apply a directive on a DOM element using getElementById in angular 7


I have some HTML generated by a third party (plotly), and I would love to apply a directive that we already have on one of the DOM elements it creates.

The directive opens a colorPicker on click and sets colors to strings.

I can reach the element with querySelector, or getElementById, but how can I transform / wrap it so I can add a directive?

I tried:

 const el = document.getElementById('myEl');
 const comp = new ElementRef(el)

or:

const comp = this.renderer.selectRootElement(el)

but comp didn't turn up to be helpful


Solution

  • If this HTML is generated, I suggest to add a wrapper component for this library. Inside, you can have a DIV wrapping the place where you would put your generated HTML and on that wrapper you can add your directive.

    Something like that:

    @Component({
        selector: 'lib-wrapper',
        template: '<div myDirective><div #placeholder></div></div>',
    })
    export class LibWrapperComponent {
        @ViewChild('placeholder')
        placeholder: ElementRef<HTMLElement>;
    
        ngAfterViewInit() {
            myLibrary.doStuffOnElement(this.placeholder.nativeElement);
        }
    }
    

    Edit: If your directive does all that you need but your problem is that the element you need to bind it to is nested deep, you can add input to your directive with a selector:

    @Directive({
      selector: 'clickListener',
    })
    export class ClickListener {
      @Input()
      clickListenerSelector = '';
    
      constructor(
        @Inject(ElementRef) private readonly elementRef: ElementRef<HTMLElement>,
      ) {}
    
      @HostListener('click', ['$event.target'])
      onClick(target: HTMLElement) {
        if (this.host.contains(target) {
           // Do your logic here
        }
      }
    
      private get host(): HTMLElement {
        return !this.clickListenerSelector
          ? this.elementRef.nativeElement
          : (this.elementRef.nativeElement.querySelector(this.clickListenerSelector) || this.elementRef.nativeElement);
      }
    
    }
    

    This way you can add your directive to the wrapper element and pass selector to it. In case you did not pass a selector it would work like it works now, if selector didn't find anything it would also use its ElementRef element, like it does not.