Search code examples
angularangular-componentsangular-template

How can I dynamically load a image in the body tag in each component?


I am new at Angular, I have tried to create this example to make me understand. I would like that when I navigate from one component to another, I dynamically load the background image to the body tag, I do not know why it does not load.

In each component I include in the styles section, the image that I want to change for the body of each component.

Or what can I do? I just want to have a different background image for the components that are loaded in my router-outlet (in my case, mainComponent and anotherComponent)

This is my code:

  @Component({
    selector: 'another',
    template: '<a routerLink="/">main</a>',
    styles: [`body {
     position: fixed;
     min-width: 100%;
     background-image: url("https://source.unsplash.com/1920x1080?landscape") !important;
     background-repeat: no-repeat;
     background-size: 100%;
     background-position: center;
     background-size: cover;
    }`]

second component:

@Component({
  selector: 'main',
  template: '<a routerLink="/another">anotherComponent</a>',
  styles: [`body {
      position: fixed;
      min-width: 100%;
      background-image: url("https://source.unsplash.com/1920x1080?stars") !important;
      background-repeat: no-repeat;
      background-size: 100%;
    background-position: center;
      background-size: cover;
}`]

This is the live code:

https://stackblitz.com/edit/angular-9kbx4q


Solution

  • In Angular you can not overwrite parent styles from components styles, because the styles of your component are encapsulated and works only for your component.

    You should add encapsulation: ViewEncapsulation.None to @Componentn({})-definition in each component, where you want override css for body tag.

    Here is an working example:

    import { Component, Input , ViewEncapsulation} from '@angular/core';
    
    @Component({
        selector: 'another',
        template: '<a routerLink="/">main</a>',
        styles: [`body {
        position: fixed;
        min-width: 100%;
        background-image: url("https://source.unsplash.com/1920x1080?landscape") !important;
        background-repeat: no-repeat;
        background-size: 100%;
        background-position: center;
        background-size: cover;
        }`],
        encapsulation: ViewEncapsulation.None
    })
    export class AnotherComponent  {
      constructor(){}
    }
    
    

    Important: By disabling the encapsulation, you components styles are adopted global and will override styles with same classes, ids or tags.

    Hint: You can use this solution, but it is better if you set background image to components own html tag.

    Better solution for your use case:

    Add an wrapper div to your another and main components template. Then add your styles to this wrapper div. Like this:

    another.component.ts

    @Component({
      selector: 'another',
      template: '<div><a routerLink="/">main</a></div>',
      styles: [`div {
        position: fixed;
        min-width: 100%;
        background-image: url("https://source.unsplash.com/1920x1080?landscape") !important;
        background-repeat: no-repeat;
        background-size: 100%;
        background-position: center;
        background-size: cover;
      }`]
    })
    

    main.component.ts

    @Component({
      selector: 'main',
      template: '<div><a routerLink="/another">anotherComponent</a></div>',
      styles: [`div {
        position: fixed;
        min-width: 100%;
        background-image: url("https://source.unsplash.com/1920x1080?stars") !important;
        background-repeat: no-repeat;
        background-size: 100%;
        background-position: center;
        background-size: cover;
      }`]
    })
    

    Here is working example on stackblitz.

    Read more about ViewEncapsulation on angular docs.