Accessing `selector` from within an Angular 2 component
Asked Answered
S

4

29

I'm trying to figure out how I can access the selector that we pass into the @Component decorator.

For example

@Component({
  selector: 'my-component'
})
class MyComponent {
  constructor() {
     // I was hoping for something like the following but it doesn't exist
     this.component.selector // my-component
  }
}

Ultimately, I would like to use this to create a directive that automatically adds an attribute data-tag-name="{this.component.selector}" so that I can use Selenium queries to reliably find my angular elements by their selector.

I am not using protractor

Seamaid answered 12/5, 2016 at 13:21 Comment(0)
S
38

Use ElementRef:

import { Component, ElementRef } from '@angular/core'

@Component({
  selector: 'my-component'
})
export class MyComponent {
  constructor(elem: ElementRef) {
    const tagName = elem.nativeElement.tagName.toLowerCase();
  }
}
Sublett answered 3/3, 2017 at 13:9 Comment(1)
This probably is the only way to do it now. The older (now broken) way was better since it didn't require adding an injection and it would be accessible without requiring an instance, which I use when writing end to end tests to minimize duplication.Seamaid
P
13

Since Angualr v14.1 you can do this:

import { reflectComponentType } from '@angular/core';

@Component({
  selector: 'my-component'
})
class MyComponent {
  constructor() {
     const metadata = reflectComponentType(MyComponent);
     const selector = metadata.selector // my-component
  }
}
Percent answered 9/3, 2023 at 16:9 Comment(0)
A
9

OUTDATED See https://mcmap.net/q/480119/-accessing-selector-from-within-an-angular-2-component

You need to get the metadata associated with your component:

Important Note Annotations get stripped out when you run the AOT compiler rendering this solution invalid if you are pre compiling templates

@Component({
  selector: 'my-component'
})
class MyComponent {
  constructor() {
    // Access `MyComponent` without relying on its name
    var annotations = Reflect.getMetadata('annotations', this.constructor);
    var componentMetadata = annotations.find(annotation => {
      return (annotation instanceof ComponentMetadata);
    });
    var selector = componentMetadata.selector // my-component
  }
}
Aspen answered 12/5, 2016 at 13:25 Comment(4)
This looks promising, how is Reflect.getMetadata able to know that it's supposed to look for metadata for MyComponent if we're not telling it anything? I'm currently getting an error when I call Reflect.getMetadata('annotations'); The error is Reflect.getMetadata('annotations') VM61 angular2.sfx.dev.js:2652 Uncaught TypeError(…)getMetadata @ Reflect.getMetadata('annotations', this, 'annotations') It looks like it needs two extra parametersSeamaid
Fixed your answer by passing this.constructor as the second argument.Seamaid
Please qualify this answer with the version of Angular 2 to which it applies - as of release 2.3.0 this seems to be out-of-dateSamala
github.com/angular/angular/issues/13495#issuecomment-267314384 :-(Obbligato
M
8

Here's an alternative if you need the selector name without access to the component's ElementRef:

const components = [MyComponent];

for (const component of components) {
  const selector = component.ɵcmp.selectors[0][0];
  console.log(selector);
}

Honestly, this first method feels rather hacky and who knows if this ɵ is supposed to just be for internal use? I thought I'd include it so that maybe someone could shed some light on it?

So, this is probably a safer route:

constructor(private factory: ComponentFactoryResolver) {
  const components = [MyComponent];

  for (const component of components) {
    const { selector } = this.factory.resolveComponentFactory(component);
    console.log(selector);
  }
}
Meshach answered 21/7, 2021 at 3:50 Comment(3)
The first solution depends on internal/private values. However, the second solution looks solid.Seamaid
Second option is definitely the most solid option I've seen so far. Thanks for pointing that out drewKavita
ComponentFactoryResolver is deprecated as of Angular v13. Which is a shame because I'm working with Angular elements and I could've used this to define the custom element in the AppModule constructor, so I can't inject the ViewContainerRef.Chiasma

© 2022 - 2024 — McMap. All rights reserved.