Reputation: 1058
I have created a shared component(<nextgen-table></nextgen-table>
) based on Mat-table
(Angular Material). While using this component inside a project, discover that I need to change the behavior(width) of the table columns.
I have exported nextgen-table
in my other components (let's say X, Y ) where nextgen-table
is, of course, a child component.
To change the width of specific columns of the mat-table I have to use something like this:
mat-cell:nth-child(1),
mat-header-cell:nth-child(1) {
flex: 0 0 40%;
text-align: left;
}
mat-cell:nth-child(2),
mat-header-cell:nth-child(2) {
flex: 0 0 20%;
}
The above CSS code I was implementing in the X.component.css and it was not working because of encapsulation I guess.
After a little bit of search, I have found the solution which worked correctly just by adding the encapsulation: ViewEncapsulation.None
in the Component decorator of x.component.ts
. After this solution, I was navigating from the component X to the Component Y in which I didn't implement the above CSS code. But the component Y had the first two columns as I wanted only for component X but somehow component Y had also which I didn't want for the component Y.
So my question is how can I update the style of nextgen-table
from the parent component which only applies for the parent component and not in the other components.
I have also tried to use
:host(mat-cell:nth-child(1)){
flex: 0 0 40%;
text-align: left;
}
:host(mat-header-cell:nth-child(1)) {
flex: 0 0 40%;
text-align: left;
}
but nothing happened/changed.
Thanks in advance for the help
Upvotes: 1
Views: 16652
Reputation: 685
The only reliable way i've ever found is to use ::ng-deep
Anything else seems to be "hit or miss" intermittently
Upvotes: 0
Reputation: 3735
All you need to do is use both :host
and ::ng-deep
pseudo-class selectors in your X or Y component.
Here is the working demo.
And here is the quick explanation.
styles which are written for the <nextgen-table>
inside let say nextgen-table.component.css
are get encapsulated by angular by adding a specific attributes for each style. i.e if you have written something like,
.mat-header-cell{
background-color: #ff0000;
}
then it becomes something like,
.mat-header-cell[_ngcontent-c29]
background-color: #ff0000;
}
So all we need to do is to override this style inside our component X or component Y.
We have ::ng-deep
pseudo-selector which will prevent angular from encapsulating out component's css.
But using ::ng-deep
will leak our css on to parent components as well. So to prevent that we need to encapsulate out ::ng-deep
style. to do that we can use :host
pseudo-selector.
so if we write following css inside component X,
:host ::ng-deep .x-table .mat-header-cell{
background-color: lightblue;
}
then it will become something like,
[_nghost-c82] .x-table .mat-header-cell {
background-color: lightblue;
}
now this above css selection has higher precedence than the style written in the table component .mat-header-cell[_ngcontent-c29]
.
That's how we can override child component's style inside any parent component. I hope this will help.
Update:
As you can see in Angular's official docs that ::ng-deep
is deprecated.
The shadow-piercing descendant combinator is deprecated and support is being removed from major browsers and tools. As such we plan to drop support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until then ::ng-deep should be preferred for a broader compatibility with the tools.
So if you don't want to be dependent on ::ng-deep
than,
You can use ViewEncapsulation.None
in your <nextgen-table>
table component which you have already tried. Demo here
And to prevent the style from bleeding into other components you can scope the table's style by adding the selector in front of all the styles like this.
nextgen-table .mat-header-cell{
background-color: #ff0000;
}
and then you do the same for your X component.
ViewEncapsulation.None
disable encapsulation in side your X component,
@Component({
selector: "app-x",
styleUrls: ["x.component.css"],
templateUrl: "x.component.html",
encapsulation: ViewEncapsulation.None
})
export class XComponent {
}
then override the table's component style in x.compoent.css
app-x nextgen-table .mat-header-cell{
background-color: lightblue;
}
If you don't want to disable the view encapsulation then you can write styles directly into global stylesheet styles.css
.
Just remember that It's all about overriding and scoping your styles.
Upvotes: 5
Reputation: 34425
You can use the ::ng-deep
pseudo class, to specifically target child elements without changing the view encapsultation for the whole component (which would mean that all its rules would leak).
Note: ::ng-deep
has been marked as deprecated for since a few major versions now, but they will not remove suppoprt until they have a workaround.
parentX.html
<div class="compContainer">
<nextgen-table></nextgen-table>
</div>
parentX.scss
::ng-deep .compContainer nextgen-table
{
mat-cell:nth-child(1),
mat-header-cell:nth-child(1) {
flex: 0 0 40%;
text-align: left;
}
mat-cell:nth-child(2),
mat-header-cell:nth-child(2) {
flex: 0 0 20%;
}
}
You could also add your css rules to the global style.scss
file.
//Rules for parent X
app-parent-componentX .compContainer nextgen-table
{
mat-cell...
}
//Rules for a parent Y
app-parent-componentY .compContainer nextgen-table
{
mat-cell...
}
Upvotes: 5