Optiq
Optiq

Reputation: 3182

How do we load an angular component's styles into an iframe?

I'm working on a component that renders other components into an iframe. It renders successfully however I noticed the styles aren't being passed into it. I tried using the styles array in the @Component instead of linking to an external stylesheet which failed. I also added them to the template inside of a <style> tag which also failed. I see how we can access the contentDocument and or contentWindow to pass data into the DOM of the iframe which I planned on using a service to do instead of having to dig around at things I can't even touch once they're inside the iframe. Is there a way to pass the styles into it without having to make a data object then a couple functions inside the nested component to create and apply them? So far this is what my code looks like.

Component

import { PropertyDisplayComponent } from './components/property-display/property-display.component';

@Component({
  selector: 'responsive-shell',
  templateUrl: './responsive-shell.component.html',
  styleUrls: ['./responsive-shell.component.css']
})

export class ResponsiveShellComponent implements OnInit, AfterViewInit {

  @ViewChild('compFrame', {static: false}) CompFrame: ElementRef | undefined;
  doc: any;
  compRef: ComponentRef<PropertyDisplayComponent> | undefined;

  constructor(private VcRef: ViewContainerRef, private resolver: ComponentFactoryResolver) { }

  public onLoad(){
    this.doc = this.CompFrame?.nativeElement.contentDocument || this.CompFrame?.nativeElement.CompFrame.contentWindow;
    this.createComponent();
  }

  private createComponent():void{
    const compFactory = this.resolver.resolveComponentFactory(PropertyDisplayComponent);
    this.compRef = this.VcRef.createComponent(compFactory);
    this.compRef.location.nativeElement.id = 'propertyDisplay';
    this.doc.body.appendChild(this.compRef.location.nativeElement);
  }

  ngOnInit(): void {
  }

  ngAfterViewInit():void{
    this.onLoad();
  }

}

Template

<section class="shell">
    <iframe class="iframeShell" #compFrame></iframe>
</section>

Is there something I should be doing differently or does anyone see where I can add in the stylesheet?

UPDATE I discovered the styling works if we do it inline, but would prefer a different solution if we can just pass the stylesheet some type of way.

Upvotes: 1

Views: 2395

Answers (1)

nstuyvesant
nstuyvesant

Reputation: 1516

Try changing the component decoration from this...

@Component({
  selector: 'responsive-shell',
  templateUrl: './responsive-shell.component.html',
  styleUrls: ['./responsive-shell.component.css']
})

to this...

@Component({
  selector: 'responsive-shell',
  templateUrl: './responsive-shell.component.html',
  styleUrls: ['./responsive-shell.component.css'],
  encapsulation: ViewEncapsulation.ShadowDom
})

More on the topic of ViewEncapsulation.

Note: this only works for modern browsers because it relies on the browser's support for the Shadow DOM API. I've experienced wonky behavior if you are loading several SCSS files from your component's SCSS but local styles work well.

Upvotes: 2

Related Questions