How to remove extra wrapping elements in the rendered HTML?
Angular components are directives with templates. According to this:
Directive configuration @Directive({ property1: value1, ... })
selector: '.cool-button:not(a)' Specifies a CSS selector that identifies this directive within a template. Supported selectors include element, [attribute], .class, and :not().
So component selectors can be also attribute selectors. For your example, instead of writing this:
parent.component.html:
<app-button>
<app-text>
My Text
</app-text>
</app-button>
write this:
parent.component.html:
<button app-button>
<span app-text>My Text</span>
</button>
where :
app-button.component.ts
...
selector: '[app-button]',
template: `<ng-content></ng-content>
...
app-text.component.ts
...
selector: '[app-text]',
template: `<ng-content></ng-content>`
...
this would be rendered as you expected:
Update after your comment about styling those buttons:
To style the buttons from inside the button component, and set class in parent component, use :host-context
pseudo-class. It is not deprecated and works well
button.component.css
:host-context(.button-1) {
background: red;
}
:host-context(.button-2) {
background: blue;
}
app.component.html
<button app-button class="button-1">
<span app-text>My Text</span>
</button>
<button app-button class="button-2">
<span app-text>My Text</span>
</button>
Here is the DEMO
I had a similar issue. I'll provide my solution in case someone else has the same problem.
My component should be able to be used either within other components or as a route from <router-outlet></router-outlet>
. When I used the selector as an attribute [my-component]
things worked perfectly provided it was used within other components. But when created by <router-outlet></router-outlet>
a <div>
were created automatically.
To avoid that, we can simply use multiple selectors, and consider that the selectors can be combined.
Consider this: I want my component to use the attribute my-component
and if it ever should be created by the <router-outlet></router-outlet>
it should be wrapped in a <section></section>
. To achieve this simply use:
@Component(
selector: 'section[my-component], my-component',
...
)
The result will be, if used inside another tag:
<whatevertag my-component>
... component content ...
</whatertag>
If used as a route:
<section my-component>
... component content ...
</section>