diff --git a/packages/core/src/render3/instructions/instructions.ts b/packages/core/src/render3/instructions/instructions.ts
index 4f64b431ff..e3c3e78934 100644
--- a/packages/core/src/render3/instructions/instructions.ts
+++ b/packages/core/src/render3/instructions/instructions.ts
@@ -547,6 +547,13 @@ export function elementContainerStart(
const tNode =
createNodeAtIndex(index, TNodeType.ElementContainer, native, tagName, attrs || null);
+
+ if (attrs) {
+ // While ng-container doesn't necessarily support styling, we use the style context to identify
+ // and execute directives on the ng-container.
+ setNodeStylingTemplate(tView, tNode, attrs, 0);
+ }
+
appendChild(native, tNode, lView);
createDirectivesAndLocals(tView, lView, localRefs);
attachPatchData(native, lView);
@@ -559,6 +566,25 @@ export function elementContainerStart(
executeContentQueries(tView, tNode, lView);
}
+/**
+ * Appropriately sets `stylingTemplate` on a TNode
+ *
+ * Does not apply styles to DOM nodes
+ *
+ * @param tNode The node whose `stylingTemplate` to set
+ * @param attrs The attribute array source to set the attributes from
+ * @param attrsStartIndex Optional start index to start processing the `attrs` from
+ */
+function setNodeStylingTemplate(
+ tView: TView, tNode: TNode, attrs: TAttributes, attrsStartIndex: number) {
+ if (tView.firstTemplatePass && !tNode.stylingTemplate) {
+ const stylingAttrsStartIndex = attrsStylingIndexOf(attrs, attrsStartIndex);
+ if (stylingAttrsStartIndex >= 0) {
+ tNode.stylingTemplate = initializeStaticStylingContext(attrs, stylingAttrsStartIndex);
+ }
+ }
+}
+
function executeContentQueries(tView: TView, tNode: TNode, lView: LView) {
if (isContentQueryHost(tNode)) {
const start = tNode.directiveStart;
@@ -636,12 +662,7 @@ export function elementStart(
// value is evaluated). When the template is allocated (when it turns into a context)
// then the styling template is locked and cannot be further extended (it can only be
// instantiated into a context per element)
- if (tView.firstTemplatePass && !tNode.stylingTemplate) {
- const stylingAttrsStartIndex = attrsStylingIndexOf(attrs, lastAttrIndex);
- if (stylingAttrsStartIndex >= 0) {
- tNode.stylingTemplate = initializeStaticStylingContext(attrs, stylingAttrsStartIndex);
- }
- }
+ setNodeStylingTemplate(tView, tNode, attrs, lastAttrIndex);
if (tNode.stylingTemplate) {
// the initial style/class values are rendered immediately after having been
diff --git a/packages/core/test/acceptance/content_spec.ts b/packages/core/test/acceptance/content_spec.ts
index 12898d4a71..63b6348431 100644
--- a/packages/core/test/acceptance/content_spec.ts
+++ b/packages/core/test/acceptance/content_spec.ts
@@ -166,5 +166,63 @@ describe('projection', () => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('inline()ng-template(onetwothree)');
});
+
+ describe('on containers', () => {
+ it('should work when matching attributes', () => {
+ let xDirectives = 0;
+ @Component({selector: 'selector-proj', template: ''})
+ class SelectedNgContentComp {
+ }
+
+ @Directive({selector: '[x]'})
+ class XDirective {
+ constructor() { xDirectives++; }
+ }
+
+ @Component({
+ selector: 'main-selector',
+ template:
+ 'Hello world!'
+ })
+ class SelectorMainComp {
+ }
+
+ TestBed.configureTestingModule(
+ {declarations: [XDirective, SelectedNgContentComp, SelectorMainComp]});
+ const fixture = TestBed.createComponent(SelectorMainComp);
+
+ fixture.detectChanges();
+ expect(fixture.nativeElement).toHaveText('Hello world!');
+ expect(xDirectives).toEqual(1);
+ });
+
+ it('should work when matching classes', () => {
+ let xDirectives = 0;
+ @Component({selector: 'selector-proj', template: ''})
+ class SelectedNgContentComp {
+ }
+
+ @Directive({selector: '.x'})
+ class XDirective {
+ constructor() { xDirectives++; }
+ }
+
+ @Component({
+ selector: 'main-selector',
+ template:
+ 'Hello world!'
+ })
+ class SelectorMainComp {
+ }
+
+ TestBed.configureTestingModule(
+ {declarations: [XDirective, SelectedNgContentComp, SelectorMainComp]});
+ const fixture = TestBed.createComponent(SelectorMainComp);
+
+ fixture.detectChanges();
+ expect(fixture.nativeElement).toHaveText('Hello world!');
+ expect(xDirectives).toEqual(1);
+ });
+ });
});
-});
\ No newline at end of file
+});
diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json
index aca1ed856b..2cb9a466ab 100644
--- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json
+++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json
@@ -659,6 +659,9 @@
{
"name": "setIsParent"
},
+ {
+ "name": "setNodeStylingTemplate"
+ },
{
"name": "setPreviousOrParentTNode"
},
diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json
index b0925d8341..7272669301 100644
--- a/packages/core/test/bundling/todo/bundle.golden_symbols.json
+++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json
@@ -1271,6 +1271,9 @@
{
"name": "setIsParent"
},
+ {
+ "name": "setNodeStylingTemplate"
+ },
{
"name": "setPlayerBuilder"
},