2

What's the better way of manipulating the DOM to change the background of a specific div, rather than using document.getElementById('id').style.backgroundImage.

I'm trying to change backgrounds as I change my Url, but the only way I could think and easy is using document.getElementById()

changeBg() {
 var urlPath = window.location.pathname.split('/');
  switch (urlPath[4]) {
    case "Refreshments%20North":
     document.getElementById('homeBg').style.backgroundImage = "url('./assets/imgs/spur-2.jpg')";
     break;
   ... more cases
    default:
     document.getElementById('homeBg').style.backgroundImage = "url('./assets/imgs/background.jpg')";
  }
}

I also tried Renderer dependency but how do I target homeBg using this?

this.renderer.setElementStyle(this.elRef.nativeElement, 'background-image', "url(./assets/imgs/spur-2.jpg)"); 

Template -- is basically just a div

<nav></nav>
<div id="homeBg"></div>

Edit -- Moved my changeBg() to my sharedService

public changeBg() {
var urlPath = window.location.pathname.split('/');
switch (urlPath[4]) {
  case "Refreshments%20North":
    this.homeBg = this.sanitizer.bypassSecurityTrustStyle("url('./assets/imgs/spur-2.jpg')");
    break;
  default:
    this.homeBg = this.sanitizer.bypassSecurityTrustStyle("url('./assets/imgs/background.jpg')");
  }
}

Calling changeBg() service in my profile component

ngOnInit() {
  this.sharedService.changeBg(); // is this correct?
}

Profile template -- like this gives me an error Cannot read property 'homeBg' of undefined

<div class="home" id="homeBg" [style.background-image]="changeBg?.homeBg"></div>

Change background with route.param.subscribe()

this.routeSub = this.route.params.subscribe(params => {
  this.sharedService.changeBg();
}
MrNew
  • 1,384
  • 4
  • 21
  • 43

2 Answers2

3

Using binding and directives is the preferred way in Angular2 instead of imperative DOM manipulation:

<div [style.background-image]="myService.homeBg"

You need to sanitize the URL for Angular to accept it. See In RC.1 some styles can't be added using binding syntax for more details.

changeBg() {
 var urlPath = window.location.pathname.split('/');
  switch (urlPath[4]) {
    case "Refreshments%20North":
     this.homeBg = this.sanitizer.bypassSecurityTrustStyle("url('./assets/imgs/spur-2.jpg')");
     break;
   ... more cases
    default:
     this.homeBg = this.sanitizer.bypassSecurityTrustStyle( "url('./assets/imgs/background.jpg')");
  }
}

See also How to add background-image using ngStyle (angular2)?

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Can you check my edit line in my question if its correct, following your example code. I moved my `changeBg()` into my sharedService. – MrNew Mar 28 '17 at 09:59
  • There seems to be a naming problem `mylocationbg` in `[style.background-image]="mylocationbg.homeBg"` points to a function but is used like a property. – Günter Zöchbauer Mar 28 '17 at 10:02
  • should I remove `mylocationbg` and just call `this.sharedService.changeBg()` in the `ngOninit`? and do `[style.background..]="changeBg.homeBg"`? Actually nope that gave me an error instead. – MrNew Mar 28 '17 at 10:08
  • If `changeBg` is the field that references your service, then yes. You might need to call `changeBg()` if the URL changes. You could to this by subscribing to the `Router` or to `window.hashchange` or what ever fits your use case. – Günter Zöchbauer Mar 28 '17 at 10:10
  • Yeah I named it `changeBg` in my service, but when I change the template to `[style.background...]="changeBg.homeBg"` I get `Cannot read property 'homeBg' of undefined`.. `ngOninit { this.sharedService.changeBg()` – MrNew Mar 28 '17 at 10:18
  • Try `[style.background...]="changeBg?.homeBg"` to not get an error while `changeBg` is not yet set. – Günter Zöchbauer Mar 28 '17 at 10:19
  • I don't see the `[style.background..]` in the template when I inspect it. Also I'm triggering `changeBg` service on my `this.route.params.subscribe()..` See my edit. – MrNew Mar 28 '17 at 10:29
  • You could try `bypassSecurityTrustUrl` or `bypassSecurityTrustResourceUrl` instead of `bypassSecurityTrustStyle`. I'm not sure yet myself when exactly use which. – Günter Zöchbauer Mar 28 '17 at 10:32
  • Still can't see it but using something like this `[style.background]="'url('+changeBg?.homeBg+')"` shows in the template but the `url()` value is `null` – MrNew Mar 28 '17 at 10:40
  • Any idea why the value is `null`? – MrNew Mar 28 '17 at 11:00
  • because string concatenation removes the sanitization marker. – Günter Zöchbauer Mar 28 '17 at 11:45
  • also tried `[style.background]="changeBg?.homeBg"` but again I don't see any style in the template. Is there any work around? – MrNew Mar 28 '17 at 12:00
  • Yeah it works if calling directly from its component but somehow not when its coming from a service :/ – MrNew Mar 28 '17 at 16:23
  • Try adding `
    {{changeBg?.homeBg}}
    ` to see what value this actually returns. (alternatively `
    {{changeBg?.homeBg | json}}
    `)
    – Günter Zöchbauer Mar 28 '17 at 16:24
  • `
    {{changeBg?.homeBg | json}}
    ` returns `null`
    – MrNew Mar 28 '17 at 16:33
  • Then `homeBg` doesn't get a value assigned. – Günter Zöchbauer Mar 28 '17 at 16:34
  • Thought this would assign a value `this.homeBg = this.sanitizer.bypassSecurityTrustStyle("url('./assets/imgs/spur-2.jpg')")` or even just `this.homeBg = "test"` – MrNew Mar 28 '17 at 16:37
  • I put a `console.log('Test')` in the `case "Refreshment..":` case and it printed the log, so its being executed, strange. – MrNew Mar 28 '17 at 16:44
  • Perhaps you have multiple instances of the service (provided more than once). Can you reproduce in the Plunker? – Günter Zöchbauer Mar 28 '17 at 16:44
  • Here's a plnkr sample, just forked yours and you should see `null` under the image https://plnkr.co/edit/lc9NAiifCvDfQKbdhUHM?p=preview, updated the plnkr removed the `switch` case. – MrNew Mar 28 '17 at 16:59
  • It should be `[style.background-image]="sharedService?.swapBackground"` – Günter Zöchbauer Mar 28 '17 at 17:04
  • I've already tried that and that wasn't showing anything even if you inspect the element. – MrNew Mar 28 '17 at 17:08
  • 1
    Sorry, I thought I added the Plunker link https://plnkr.co/edit/uUvovP5OoeNB0uLtAnEw?p=preview – Günter Zöchbauer Mar 28 '17 at 17:09
  • Ah without the `changeBg()` function :/.. now that worked. – MrNew Mar 28 '17 at 17:11
  • I updated my comment after about 2 minutes. You might have missed that. Glad to hear you could make it work. – Günter Zöchbauer Mar 28 '17 at 17:12
1

You can use template references and @ViewChild decorator:

template :

<div #myDiv id="homeBg"></div>

component :

class MyComponent implements AfterViewInit{
    @ViewChild("myDiv")
    elRef:ElementRef

    ngAfterViewInit(){
        this.renderer.setElementStyle(this.elRef.nativeElement, 'background-image', "url(./assets/imgs/spur-2.jpg)");
    }

}
n00dl3
  • 21,213
  • 7
  • 66
  • 76