Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

Possible undocumented breaking change from 2.2.0 -> 3.0.0 #405

Closed
daniel-v opened this issue May 24, 2017 · 2 comments
Closed

Possible undocumented breaking change from 2.2.0 -> 3.0.0 #405

daniel-v opened this issue May 24, 2017 · 2 comments

Comments

@daniel-v
Copy link

daniel-v commented May 24, 2017

It's related to how templates are compiled for transcluded content. If JustSomeDirective is used in a component tree where <ng-content></ng-content> is not present, both framework versions work the same. <ng-content></ng-content> changes behaviour.

I believe it is simpler to demonstrate, than explain:

import 'package:angular2/core.dart';
import 'package:angular2/platform/browser.dart';

main() {
  bootstrap(MvrApp);
}

@Component(
  selector: 'mvr',
  template: '''
  <sub-cmp>
      <div custom-attr>Expect to be green!</div>
  </sub-cmp>''',
  directives: const [SubComponent, JustSomeDirective],
)
class MvrApp {}

@Component(
  selector: 'sub-cmp',
  template: '<ng-content></ng-content>',
  styles: const [':host [custom-attr] { color: green; }'],
)
class SubComponent {}

@Directive(
    selector: '[custom-attr]'
)
class JustSomeDirective {}

Outputs:

<!--v2.2.0 outputs green text!-->
<style>[_nghost-sqw-2] [custom-attr] { color: green; }</style>
<mvr>  <sub-cmp _nghost-sqw-2="">
    <div custom-attr="">Expect to be green!</div>
</sub-cmp></mvr>

<!-- vs 3.0.0 does not show green :S -->
<style>._nghost-vrh-2 [custom-attr]._ngcontent-vrh-2 { color:green; }</style>
<mvr id="">  <sub-cmp class="_nghost-vrh-2">
    <div custom-attr="">Expect to be green!</div>
</sub-cmp></mvr>

Questions:

  • was it at all intended to work like so in v2.2.0?
  • is it a bug or a feature? :)
  • How would you achieve the same behaviour in v3.0.0+?

Edit: clarified when the change in behaviour occurs

@leonsenft
Copy link
Contributor

This actually demonstrates a long standing bug with :host that we fixed in 3.0.0. Apologies for not communicating this well enough with the release.

With ViewEncapsulation.Emulated set by default, Angular encapsulates all of a component's style within the component's view. This is achieved by adding a component-specific class (_ngcontent-<id>) to every element in the component's template, and every selector in the component's styles.

If you wish to style elements not in a component's template, such as those within a child component, or in your example, those projected via <ng-content>, you can disable scoping with the shadow piercing combinator /deep/ (or its alias >>>). This combinator prevents all following selectors from being scoped to their host component.

The reason your example works prior to 3.0.0 is because of a bug with :host that prevented the remainder of the selector from being scoped to its component. It essentially behaved the same as :host /deep/.

Notice the difference in the output styles you've shown. Prior to 3.0.0, the [custom-attr] selector is missing the component-specific scoping class. In 3.0.0+ you need to explicitly use /deep/ to specify you're styling something outside the component template.

Answers:

  • No, it was unintentional that this worked prior to 3.0.0.
  • There was a bug with :host that enabled your example to work.
  • You can rewrite your selector as :host /deep/ [custom-attr].

Hope this helps!

@daniel-v
Copy link
Author

It definitely helped! Extra thanks for explaining.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants