2

I have this button, that I use in multiple places throughout my site.

Because of that, I moved it to Component. I call it GetInvolvedButtonComponent.

However, I can't use this Component right now because Angular is wrapping a special HTML tag around it. That cause issue.

How do I render the HTML straight into the section without it being wrapped in that tag?

Here's what I have thus far:

get-involved-button.component.html

<!-- TODO: This is going to route to another page called "Get Involved" -->
<a class="btn btn-primary center" routerLink="/contact">Get Involved!</a>

get-involved-button.component.ts

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

@Component({
  selector: "[get-involved-button]",
  templateUrl: "./get-involved-button.component.html",
  styleUrls: ["./get-involved-button.component.css"],
})
export class GetInvolvedButtonComponent implements OnInit {
  constructor() {}

  ngOnInit(): void {}
}

When I inspect the DOM element in the developer console, this is what I see:

enter image description here

5
  • Can you post the wrapper html screenshot or code ? Commented Jul 19, 2020 at 15:11
  • 1
    If it is a component, there is no way to avoid having an html tag for the component. A workaround is to use some css that practically ignores the container element: ':host { display: contents; }` Check for compatibility. Commented Jul 19, 2020 at 15:23
  • @alou, really you can use as selector a name between [ and ] and you can applied to any html tag, e.g. a div Commented Jul 19, 2020 at 18:28
  • May I see what that looks like, for future reference? It's been literally years since I've done any Angular, and I didn't know this Commented Jul 20, 2020 at 1:04
  • @MikeWarren, he means using as component selector an actual html element, eg [div] which will practically render your component for all div tags. I don't know if that's really an option, but it would work. Commented Jul 20, 2020 at 18:22

3 Answers 3

2

The CSS solution works well, but it is not perfect:

:host { display: contents; }

This solution say to browser that the wrapper component tag must be ignored.

But this solution do no apply the right style if it is this:

table > :not(caption) > * > * { border-bottom-width: 1px; }

This CSS apply the border width to element in 3° descendant. For example:
tbody > tr > td

But if DOM structure contains the Angular wrapper, the 3° descendant is tr:
tbody > appMyTableRows > tr

To solve this issue I am using another solution: ng-container + ViewContainerRef.

Most complex but better solution

The solution is to draw the entire component inside a ng-template, then it will be rendered in caller component using ng-content.

How to draw component template:

<ng-template #bodyTempl>
  <tr>
    <td>This is</td>
    <td>the content</td>
    <td>of Component.</td>
  </tr>
  <tr>
    <td>This is</td>
    <td>the content</td>
    <td>of Component.</td>
  </tr>
</ng-template>

Then in Component code we must add something like this:

@ViewChild("bodyTempl") bodyTemplate: TemplateRef<any>;

As last step, we need to change how we use the component in template:

<table>
  <thead>
    <tr>
      <th>head</th>
      <th>head</th>
      <th>head</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>row 1</td>
      <td>row 1</td>
      <td>row 1</td>
    </tr>
    <app-my-table-tr #childComRef></app-my-table-tr>
    <ng-content *ngTemplateOutlet="childComRef.bodyTemplate"></ng-content>
  </tbody>
</table>

The HTML result shows the "app-my-table-tr" tag like child of TBODY, but it is empty. And the content of component will be injected like sibling of the component:

<table>
  <thead>
    <tr>
      <th>head</th>
      <th>head</th>
      <th>head</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>row 1</td>
      <td>row 1</td>
      <td>row 1</td>
    </tr>
    <app-my-table-tr _ngcontent-...></app-my-table-tr>
    <tr>
      <td>This is</td>
      <td>the content</td>
      <td>of Component.</td>
    </tr>
    <tr>
      <td>This is</td>
      <td>the content</td>
      <td>of Component.</td>
    </tr>
  </tbody>
</table>

To a perfect solution, write this in CSS of Component, so the wrapper will not rendered:

:host { display: none; }

(source: https://blog.josematos.work/how-to-render-an-angular-component-without-any-wrapping-tag-5084c84e0a62)

Sign up to request clarification or add additional context in comments.

1 Comment

you have save my life.
1

Per @alou's comment on here, I just had to

:host { display:contents }

inside the component's CSS file, and it work.

Comments

1

For me,

:host {
    display: contents;
}

Works perfectly!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.