Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Alec Irwin
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Alec Irwin

Routable View Components Don't Need Selectors In Angular 4.4.4 - But They May Be Helpful

By Ben Nadel on

For the the most part, Angular Directives need to provide a "selector" in their @Component() or @Directive() meta-data definitions. This allows Angular to locate and associate HTML entities with the appropriate directives when parsing templates. With routable components, however - those that are injected into a template by the Router and the router-outlet directives - selectors aren't required. That said, they may be helpful in debugging nested view-rendering logic.

Run this demo in my JavaScript Demos project on GitHub.

Ultimately, when a routable component is injected into a parent view, the Angular Router has to inject it as a piece of markup - it has to be come part of the rendered DOM (Document Object Model). If the routable component has a selector, Angular will use the selector to create an Element node. If the routable component omits a selector, Angular will use "ng-component" as the injected Element tag name.

To see this in action, I've created a simple Angular application that contains a single router-outlet that can switch between two view components: AViewComponent and BViewComponent. Since the parent view is somewhat irrelevant for this exploration, I'm going to skip over the application module and the root component and proceed directly to our routable views. First, let's look at AViewComponent:

  • // Import the core angular services.
  • import { Component } from "@angular/core";
  •  
  • // ----------------------------------------------------------------------------------- //
  • // ----------------------------------------------------------------------------------- //
  •  
  • @Component({
  • // NOTE: Since routable views aren't embedded in template logic, we don't need to
  • // provide a SELECTOR - Angular will inject this component automatically as part
  • // of the router-outlet logic (using the "ng-component" tag).
  • styleUrls: [ "./a-view.component.css" ],
  • template:
  • `
  • <h3>
  • A-View Component
  • </h3>
  •  
  • <p>
  • This is the a-view component, noice!
  • </p>
  • `
  • })
  • export class AViewComponent {
  • // ...
  • }

As you can see, in this view's @Component() meta-data, there is no "selector" property. With routable components, this isn't required. But, it can be used. And, we are going to use it in the BViewComponent:

  • // Import the core angular services.
  • import { Component } from "@angular/core";
  •  
  • // ----------------------------------------------------------------------------------- //
  • // ----------------------------------------------------------------------------------- //
  •  
  • @Component({
  • // For this routable component, we're going to include a SELECTOR even though it
  • // isn't strictly necessary (so that we can see how the view output is affected).
  • selector: "b-view",
  • styleUrls: [ "./b-view.component.css" ],
  • template:
  • `
  • <h3>
  • B-View Component
  • </h3>
  •  
  • <p>
  • This is the b-view component, sweet!
  • </p>
  • `
  • })
  • export class BViewComponent {
  • // ...
  • }

As you can see, in this view's @Component() meta-data, we're using the selector value of "b-view".

Now, if we run this application in the browser and navigate to the AViewComponent, we get the following Document Object Model rendering:


 
 
 

 
 Selectors aren't required in routable components in Angular 4. 
 
 
 

As you can see, the AViewComponent is being injected into the DOM using the "ng-component" element tag name. And, if we navigate to the BViewComponent, we get the following Document Object Model rendering:


 
 
 

 
 Selectors can be used in routable components, affecting the element tag name. 
 
 
 

This time, the selector provided by the component - "b-view" - is being used when Angular injects the component into the DOM.

Internally to the routable view component, these two outcomes are essentially the same. In both cases, the view component will render; and, in both cases, the view component's CSS will successfully be applied - ":host" isn't coupled to the element tag name).

But, providing a selector is helpful for the human factor. It's helpful when debugging a routable application because a tree of "ng-content" elements isn't exactly intuitive when you're inspecting elements in the Chrome Developer Tools. And, providing a selector may also make it easier to override styles in the parent component. You could attach styles to the "ng-component" selector; however, given the fact that a parent component may contain multiple router-outlet elements (for named and unnamed views), providing a unique local handle would make CSS selectors a bit more intuitive.

Now, to be clear, I'm not advocating that all view components provide selectors. To be honest, I'm on the fence about it. Part of me loves the fact that I can omit data that isn't strictly necessary for the routable component tree; but, I do see value in having the selectors present, especially for debugging (and I've been doing a lot of debugging lately with the Router in Angular 4). I suppose the best take-away here is that we have the flexibility to do what adds the most value in the given context.



Looking For A New Job?

Ooops, there are no jobs. Post one now for only $29 and own this real estate!

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.