1

I'd like to know if there's a way to tell Angular to generate a DIV instead of a new tag when inserting a component in a router-outlet. Right now, I have this component code:

import { Component, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-fwc-vpn-main',
  templateUrl: './fwc-vpn-main.component.html',
  styleUrls: ['./fwc-vpn-main.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class FwcVpnMainComponent implements OnInit {

  numbers = new Array(35);

  constructor() { }

  ngOnInit() {
  }

}

Which renders to this in the final HTML:

<router-outlet></router-outlet>
<app-fwc-vpn-main class="ng-star-inserted"> ... </app-fwc-vpn-main>

What I would need is to generate a div with some added classes, so the final result would be something like this:

<router-outlet></router-outlet>
<div app-fwc-vpn-main class="grid-y medium-grid-frame"> ... </div>

NOTE: I need to add the grid-y and medium-grid-frame classes so the app has the correct layout. This is the main reason I want to change the inserted tag for this div.

Thanks in advance,

Fel
  • 4,428
  • 9
  • 43
  • 94

3 Answers3

5

In angular selector may be declared as one of the following:

  • element-name: select by element name.
  • .class: select by class name.
  • [attribute]: select by attribute name.
  • [attribute=value]: select by attribute name and value.
  • :not(sub_selector): select only if the element does not match the sub_selector.
  • selector1, selector2: select if either selector1 or selector2 matches.

So when angular compiles Component/Directive metadata it parses selector by using CssSelector and keep all parsed data like:

[
  {
    "element": null,
    "classNames": [
      "grid-y",
      "medium-grid-frame"
    ],
    "attrs": [
      "app-fwc-vpn-main",
      ""
    ],
    "notSelectors": []
  }
]

Angular router creates component dynamically so each of our routed components will have Host view. For Host view angular compiler prepares template based on metadata received from CssSelector:

/** Gets a template string for an element that matches the selector. */
getMatchingElementTemplate(): string {
    const tagName = this.element || 'div';
    const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : '';

    let attrs = '';
    for (let i = 0; i < this.attrs.length; i += 2) {
      const attrName = this.attrs[i];
      const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : '';
      attrs += ` ${attrName}${attrValue}`;
   }

   return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` :
                                                  `<${tagName}${classAttr}${attrs}></${tagName}>`;
 }

https://github.com/angular/angular/blob/c8a1a14b87e5907458e8e87021e47f9796cb3257/packages/compiler/src/selector.ts#L91-L105

After that host template will be like:

<div class="grid-y medium-grid-frame" app-fwc-vpn-main></div>

So the following should work for you:

selector: '[app-fwc-vpn-main].grid-y.medium-grid-frame',

Example

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • That worked! Please, can you send a link to any documentation that explains this syntax? Thank you very much! – Fel Mar 05 '18 at 12:42
  • @Fel , please checkout the link I have posted in answer that would be enough for the component's each property – Vivek Doshi Mar 05 '18 at 12:47
  • @yurzui thanks for the explanation! Do you know if there is way to select based on element and attribute? E.g. `nz-content[example]` – LppEdd Jul 02 '19 at 12:20
2

Then change the selector from :

selector: 'app-fwc-vpn-main',

To

selector: '[app-fwc-vpn-main]',

And then you can use it like <div app-fwc-vpn-main></div>

@Component selector - css selector that identifies this component in a template

So you can use any css selector like

.app-fwc-vpn-main // <div class='app-fwc-vpn-main'></div>
#app-fwc-vpn-main // <div id='app-fwc-vpn-main'></div>

For more details read : Component

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
-1

Create a directive instead of a component

<div app-fwc-vpn-main class="grid-y medium-grid-frame"> ... </div>

In this case app-fwc-vpn-main is the directive. Instead of creating a component you can create a directive and render your desired template.

mast3rd3mon
  • 8,229
  • 2
  • 22
  • 46
Santosh Singh
  • 561
  • 2
  • 16