diff --git a/packages/sitecore-jss-angular/src/components/placeholder.component.spec.ts b/packages/sitecore-jss-angular/src/components/placeholder.component.spec.ts index f62e8db6a2..8e2145e3d0 100644 --- a/packages/sitecore-jss-angular/src/components/placeholder.component.spec.ts +++ b/packages/sitecore-jss-angular/src/components/placeholder.component.spec.ts @@ -34,6 +34,7 @@ class TestDownloadCalloutComponent { @Component({ selector: 'test-home', + styles: [ 'sc-placeholder[name="page-content"] { background-color: red }' ], template: ` @@ -167,6 +168,35 @@ describe('', () => { }); })); + it('should copy parent style attribute', async(() => { + const component = nonEeDevData.sitecore.route; + const phKey = 'main'; + comp.name = phKey; + comp.rendering = component; + fixture.detectChanges(); + + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + + // let's grab the style name from the parent + let parentKey = ''; + const homeComp = de.query(By.directive(TestHomeComponent)); + const homeAttributes = homeComp.nativeElement.attributes; + if (homeAttributes.length) { + const parentAttribute = homeComp.nativeElement.attributes.item(0).name; + parentKey = parentAttribute.replace('_nghost-', ''); + } + + fixture.whenStable() + .then(() => { + fixture.detectChanges(); + const downloadCallout = de.query(By.directive(TestDownloadCalloutComponent)); + expect(downloadCallout.nativeElement.attributes.item(0).name).toEqual(`_ngcontent-${parentKey}`); + }); + }); + })); + it('should skip rendering unknown components', async(() => { const phKey = 'main'; const route = { diff --git a/packages/sitecore-jss-angular/src/components/placeholder.component.ts b/packages/sitecore-jss-angular/src/components/placeholder.component.ts index 59c6a66236..f1e6e5c4b0 100644 --- a/packages/sitecore-jss-angular/src/components/placeholder.component.ts +++ b/packages/sitecore-jss-angular/src/components/placeholder.component.ts @@ -4,6 +4,7 @@ import { ComponentFactoryResolver, ContentChild, DoCheck, + ElementRef, EventEmitter, Inject, Input, @@ -11,7 +12,9 @@ import { KeyValueDiffers, OnChanges, OnDestroy, + OnInit, Output, + Renderer2, SimpleChanges, Type, ViewChild, @@ -43,11 +46,12 @@ function getPlaceholder(rendering: ComponentRendering, name: string) { `, }) -export class PlaceholderComponent implements OnChanges, DoCheck, OnDestroy { +export class PlaceholderComponent implements OnInit, OnChanges, DoCheck, OnDestroy { private _inputs: { [key: string]: any }; private _differ: KeyValueDiffer; private _componentInstances: any[] = []; private destroyed = false; + private parentStyleAttribute: string = ''; public isLoading = true; @Input() name?: string; @@ -76,9 +80,26 @@ export class PlaceholderComponent implements OnChanges, DoCheck, OnDestroy { private differs: KeyValueDiffers, private componentFactory: JssComponentFactoryService, private changeDetectorRef: ChangeDetectorRef, + private elementRef: ElementRef, + private renderer: Renderer2, @Inject(PLACEHOLDER_MISSING_COMPONENT_COMPONENT) private missingComponentComponent: Type ) { } + ngOnInit() { + // just to ensure the element exists + const elem = this.elementRef.nativeElement; + + if (elem) { + const attributes: NamedNodeMap = elem.attributes; + for (let i = 0; i < attributes.length; i++) { + const attr: Attr | null = attributes.item(i); + if (attr && attr.name.indexOf('_ngcontent') !== -1) { + this.parentStyleAttribute = attr.name; + } + } + } + } + ngOnDestroy() { this.destroyed = true; this._componentInstances = []; @@ -199,7 +220,14 @@ export class PlaceholderComponent implements OnChanges, DoCheck, OnDestroy { const componentFactory = rendering.componentFactory || this.componentFactoryResolver.resolveComponentFactory(rendering.componentImplementation); - const componentInstance = this.view.createComponent(componentFactory, index).instance; + // apply the parent style attribute _ngcontent + // work-around for https://github.com/angular/angular/issues/12215 + const createdComponentRef = this.view.createComponent(componentFactory, index); + if (this.parentStyleAttribute) { + this.renderer.setAttribute(createdComponentRef.location.nativeElement, this.parentStyleAttribute, ''); + } + + const componentInstance = createdComponentRef.instance; componentInstance.rendering = rendering.componentDefinition; if (this._inputs) { this._setComponentInputs(componentInstance, this._inputs);