3

Ok, so we know ng-deep isn't the best practice, and we know ViewEncapsulation.None gets yucky. So here's my question, what I want to do is this.

Say I have a component with;

@Input() cssClasses: string;

Then on the parent component using it I do something like;

<my-component [cssClasses]="some-css-class some-other-css-class"></my-component>

Now where those classes are being passed to I want to append the components generated selector id to those classes so when rendered in the DOM they match the css classes of the consuming component like the output we would see from the child component;

<div class="class1 class2 some-css-class some-other-css-class"></div>

The problem here is obviously viewEncapsulation will attach the component id selector the classes from the component, but NOT the ones passed into it. So without ng-deep or placing the classes in a top level inception css file they won't get applied because the selectors come out like this;

[_ngStuff-blah-123] .class1 {...}
[_ngStuff-blah-123] .class2 {...}

But since some-css-class some-other-css-class never gets the id selector from the css class derived via the @Input of the child they aren't actually applied. Unless where they're declared you have ng-deep or if it's in a top-level css that isn't attached to another component or whatever.

How does one append the context of the consuming component so you end up with output like;

[_ngStuff-blah-123] .class1 {...}
[_ngStuff-blah-123] .class2 {...}
[_ngStuff-parent-999] [_ngStuff-blah-123] .some-css-class {...}
[_ngStuff-parent-999] [_ngStuff-blah-123] .some-other-css-class {...}

Instead of just using ngStyle, ng-deep, or top-level inception instead?

Is there a way I can do something when using the child component like;

<my-component [cssClasses]="some-css-class some-other-css-class" [hostContext]="this.parent.idContext"></my-component>

So that the DOM output looks like the example above and we can be utilizing some instance specific class pass-through WITHOUT ng-deep etc? Surely I'm not the first to ask so apologies if this is a duplicate.

CuriousG
  • 97
  • 6
  • What is `top-level inception`, haven't heard that term before. But nope, those IDs are dynamic, and not publicly accessible - although this Angular v9 hack may still work https://stackoverflow.com/a/60123609/271012 – Drenai Nov 18 '21 at 22:53
  • @Drenai like you put it in the top level styles.css, it will get picked up by any elements in the document. That ecmp thing you linked to sure looks familiar though, might try it just to see. – CuriousG Nov 19 '21 at 01:21

1 Answers1

1

You want to use host-context which styles the child based on CSS classes in the parent, no need to pass the classes in. Essentially it works something like this. Here's the CSS in the child component:

:host-context(.wrapper-blue) .hello {
  color: blue
}

:host-context(.wrapper-red) .hello {
  color: red
}

HTML in the child:

<div class="hello">
  hello <!-- color depends on the class wrapping me in the parent -->
</div>

And the HTML in the parent looks like this:

<div class="wrapper-red">
 <app-child-component><app-child-component>
</div>

<div class="wrapper-blue">
 <app-child-component><app-child-component>
</div>

Its been a while since I used this so my syntax may be a little off but you get the idea. Google Angular host-context and you'll find what you need. Or look here at these SO posts:

What is the use case of :host-context selector in angular

Cannot Understand the Use of :host in components in Angular2

Nice post on it here which seems better than the others:

https://blog.angular-university.io/angular-host-context/#thehostcontextpseudoclassselector

Here's the official docs which prove that its NOT deprecated!

danday74
  • 52,471
  • 49
  • 232
  • 283
  • Yea I thought about host context, but in order for it to work the child would need to know the classes needing added by the parent before-hand. I'm trying to make it so the child is fed those classes at the instance. Or am I perhaps reading it wrong? – CuriousG Nov 19 '21 at 01:23