Kliment
Kliment

Reputation: 2270

Get root component ElementRef or ComponentRef angular 2

I'm building modal service in angular 2. I resolve most of the issues but i have problem placing the modal component in the body element in a nice angular way. I use DynamicComponentLoader.loadNextToLocation function to get the modal component and place it next to the ElementRef that is uset in DynamicComponentLoader.loadNextToLocation function. But when i don't want to place the created modal inside some component i have to manipulate DOM to insert the created modal. My question is can i use the root element in my application in the modal service? I want to achieve this when specific element isn't provided as container for the modal.

var elementRef = DOM.query('app');
this.componentLoader.loadNextToLocation(ModalBackdrop, elementRef, backdropBindings)

Upvotes: 8

Views: 25354

Answers (6)

Ajay Jagtap
Ajay Jagtap

Reputation: 21

Add a reference for ElementRef in your component's constructor:

constructor (private applicationRef: ApplicationRef) { }

You can get ElementRef with either two ways:

let container : HTMLElement;

1) container = this.applicationRef.components[0].location.nativeElement
or
2) let viewContainer = this.applicationRef.components[0];
    container = (viewContainer.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;

Upvotes: 1

Michael Kang
Michael Kang

Reputation: 52867

To get a reference to the root component, you can inject ApplicationRef:

constructor(private app:ApplicationRef)
{
      let element: ElementRef = this.app['_rootComponents'][0].location;
}

Upvotes: 9

BeetleJuice
BeetleJuice

Reputation: 40936

The available answers didn't work for me:

  • The selected answer requires the root component to have injected ElementRef.
  • The highest-voted answer relies on accessing private variables, so it could break without warning (only public API changes are considered breaking changes and are documented)
  • Other answers assume that the root component is of type AppComponent.

In my situation, I am developing a 3rd party library so I cannot make any assumption that the root is called AppComponent or that it has ElementRef injected. This is what worked for me (Angular 6.1)

private readonly rootRef: ElementRef;

constructor(private appRef: ApplicationRef) {
  this.rootRef = appRef.components[0].injector.get(ElementRef);
}

I later discovered that if I tried to inject and use the service very early after Angular bootstraps, an exception was thrown because appRef.components is still empty. So I instead modified the code to make rootRef a promise that resolves with ElementRef. This way the consuming code can call it immediately without raising an exception but will have to wait for the ElementRef to resolve:

private readonly rootRef: Promise<ElementRef>;

constructor(appRef: ApplicationRef) {
  this.rootRef = new Promise(resolve => {
    setTimeout(
      () => resolve(appRef.components[0].injector.get(ElementRef)),
      100
    );
  });
}

Upvotes: 2

Fredrik_Borgstrom
Fredrik_Borgstrom

Reputation: 3258

This works in Angular 5.2.9

Add a public ElementRef in your root component's constructor:

export class AppComponent { 

constructor (public eltRef: ElementRef) { }

And in the component where you want to access the root, do this:

private rootRef: ElementRef;
constructor(private appRef: ApplicationRef) {
    this.rootRef = (this.appRef.components[0].instance as AppComponent).eltRef;
}

Upvotes: 1

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 658067

appElementRef: ElementRef;
constructor(private applicationRef:ApplicationRef, injector: Injector) {
  this.appElementRef = injector.get(applicationRef.componentTypes[0]).elementRef;
}

The AppComponent would need to provide the elementRef field that returns the ElementRef though.

See also https://github.com/angular/angular/issues/6446

Upvotes: 8

Viktar K
Viktar K

Reputation: 1538

The problem is that to get the root ElementRef, your application should be bootstrapped. And in some situations (getting ElementRef in services) we should wait for that. My solution:

import {Injectable, ApplicationRef, ElementRef} from 'angular2/core';

@Injectable()
export class SomeService {
  private _appElementRef: ElementRef;

  constructor(appRef: ApplicationRef) {
    appRef.registerBootstrapListener(appComponentRef => {
      this._appElementRef = appComponentRef.location;
    });
  }
}

Upvotes: 1

Related Questions