Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Scoped Styles to Work With Child Components #191

Merged
merged 4 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class TestDownloadCalloutComponent {

@Component({
selector: 'test-home',
styles: [ 'sc-placeholder[name="page-content"] { background-color: red }' ],
template: `
<sc-placeholder name="page-header" [rendering]="rendering"></sc-placeholder>
<sc-placeholder name="page-content" [rendering]="rendering"></sc-placeholder>
Expand Down Expand Up @@ -167,6 +168,35 @@ describe('<sc-placeholder />', () => {
});
}));

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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import {
ComponentFactoryResolver,
ContentChild,
DoCheck,
ElementRef,
EventEmitter,
Inject,
Input,
KeyValueDiffer,
KeyValueDiffers,
OnChanges,
OnDestroy,
OnInit,
Output,
Renderer2,
SimpleChanges,
Type,
ViewChild,
Expand Down Expand Up @@ -43,11 +46,12 @@ function getPlaceholder(rendering: ComponentRendering, name: string) {
<ng-template #view></ng-template>
`,
})
export class PlaceholderComponent implements OnChanges, DoCheck, OnDestroy {
export class PlaceholderComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
private _inputs: { [key: string]: any };
private _differ: KeyValueDiffer<string, any>;
private _componentInstances: any[] = [];
private destroyed = false;
private parentStyleAttribute: string = '';
public isLoading = true;

@Input() name?: string;
Expand Down Expand Up @@ -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<any>
) { }

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 = [];
Expand Down Expand Up @@ -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);
Expand Down