1

So I have an array with the names of images files. I use Angular and this array is a property of my component class.

const backgroundImages = [
  'gym-background.jpg',
'home-background-2.jpg',
  'pt-background.jpeg'
];

I want to use these images as background-image of a card. I use Angular and have the following code in my template

<div class="card" [style.background-image]="determineBackground()">
  <div class="card-header">
    <h3 class="card-title">{{workout.name}}</h3>
    <fa-icon class="card-enlarge" [icon]="['fas', 'search-plus']"></fa-icon>
  </div>
</div>

as you can see, this will trigger determineBackground() in the component. This function returns the following string:

  determineBackground() {
    const chosenImage = this.backgroundImgs[Math.floor(Math.random() * this.backgroundImgs.length)];

    return `linear-gradient(to bottom right, rgba(#000,.5), rgba(#000,.5)), url("/assets/images/${chosenImage}")`;
  }

So, I return the value for the background-image style property. Math.floor(Math.random() * this.backgroundImgs.length) returns a value between 0 and 2 to randomly decide which image to use as background. Unfortunately it doesn't work this way, I do not see a background-image even though const chosenImage is a valid value. Could you guys help me see why?

Complete component ts file

@Component({
  selector: 'workout-list-item',
  templateUrl: './workout-list-item.component.html',
  styleUrls: ['./workout-list-item.component.scss']
})
export class WorkoutListItemComponent implements OnInit {

  backgroundImgs =  ['gym-background.jpg','home-background-2.jpg','pt-background.jpeg'];

  constructor(private router: Router) { }

  ngOnInit() { }

  determineBackground() {
    const chosenImage = this.backgroundImgs[Math.floor(Math.random() * this.backgroundImgs.length)];
return `linear-gradient(to bottom right, rgba(#000,.5), rgba(#000,.5)), url("/assets/images/${chosenImage}")`;
 }
}

Updated code

component

export class WorkoutListItemComponent implements OnInit {

  backgroundImgs = backgroundImages;
  chosenImage: string;

  constructor(private router: Router) { }

  ngOnInit() {
    this.clientId = localStorage.getItem('userId');
    this.chosenImage = this.backgroundImgs[Math.floor(Math.random() * this.backgroundImgs.length)];
    console.log('choseImage', this.chosenImage);
  }
}

template

<div
  class="card"
  [ngStyle]="{'background-image': chosenImage ? 'linear-gradient(to bottom right, rgba(#000,.5), rgba(#000,.5)), url(\'/assets/images/' + chosenImage + '\')' : ''}"
>
  <div class="card-header">
    <h3 class="card-title">{{workout.name}}</h3>
    <fa-icon class="card-enlarge" [icon]="['fas', 'search-plus']"></fa-icon>
  </div>
</div>
tilly
  • 2,229
  • 9
  • 34
  • 64

1 Answers1

2

Follow on from my comment: Calling functions from the template will cause the change detector to loop through the function dozens of times - use ngOnInit or ngAfterViewInit and set a public property on the component instead, and then bind to that

Use the following ngStyle approach in the template to avoid the url sanitization problems without the hassle

[ngStyle]="{
                'background-image': (chosenImage) ? 'url(' + chosenImage + ')' : ''         
            }"
Drenai
  • 11,315
  • 9
  • 48
  • 82
  • It's still not working unfortunately. I'll update my code on top. – tilly Jul 20 '19 at 18:25
  • So it works when I just enter the URL as background image, but with the linear gradient it's not possible. I kinda do need that gradient though because otherwise I can't see my text on top – tilly Jul 20 '19 at 18:35
  • 1
    I kinda found an alternative to add overlay to background image: I added box-shadow:inset 0 0 0 2000px rgba(255,0,150,0.1); to the card element and that has the same effect. – tilly Jul 20 '19 at 18:38