Shlomi Schwartz
Shlomi Schwartz

Reputation: 8903

AngularJS - ng-style does not update css background property

I have a service that returns image URL, and it is called using the following code:

angular.forEach(results, function (item) {
     item.img = "/images/searchItem.jpg";
     $http.post("https://my.api.com/?id=" + item.id).success(
           function (url) {
               item.img = url;
           });
});

on my view I used to have an image with ng-src attribute, that worked perfectly like so:

<img  ng-src="{{item.img}}">

Then I've decided to use background-image on a SPAN instead:

<span ng-style="{'background':'transparent url({{item.img}})'}"></span>

now the flow works only on the first run, after that I can see (in the console) the following html

<span ng-style="{'background':'transparent url(http://expertsimages.liveperson.com/images/rating/rate10.gif)'}" style="background-image: url(https://fb.lp-chat.com/images/searchItem.jpg); background-color: transparent; background-position: initial initial; background-repeat: initial initial;"></span>

which indicates that the variable updated, however the html is still on its initial state.

I tried to call apply/digest on post success, but got an error $digest already in progress (which make sense). The strage thing is that after a normal digest (for example on other ui changes) the style is being applied and I see the right image.

What am I missing here?

Update: I've created a JS fiddle that demonstrates this issue...looks like a bug in angular to me.

Upvotes: 49

Views: 29256

Answers (5)

Jules
Jules

Reputation: 55

Angular 2 has a sweet way of doing this, [style.*]="value"

<span [style.background-color]="transparent" [style.background-image]="item.img"></span>

Upvotes: -1

SW4
SW4

Reputation: 71140

Where you are currently updating your scope variable, wrap this within a $timeout call to push the updates to your scope and subsequently your view, this will effectively bump the update to the next digest avoiding the digest already in progress conflict:

    $timeout(function(){
        $scope.var = value;
    });

This question thread may give you some useful info regarding apply vs timeout etc

Upvotes: 6

cleversprocket
cleversprocket

Reputation: 1391

I ran into this as well. Instead of evaluating with {{ }}, use string + value concatenation.

This will work:

<span ng-style="{'background':'transparent url(' + item.img + ')'}"></span>)

Here's a working version of your fiddle

Upvotes: 93

user429035
user429035

Reputation: 461

you are probably facing same issue which I faced recently and solved using ng-bind .

check the answer explained in this question :

AngularJS : Why ng-bind is better than {{}} in angular?

once I used ng-bind my innerhtml is properly been updated.

Upvotes: 1

GillesC
GillesC

Reputation: 10874

It doesn't work because angular evaluate the content of single bracket only once and doesn't locate the variable you want to bind inside that string.

You could however create your own directive as such:

app.directive('backImg', function(){
    return function(scope, element, attrs){
        attrs.$observe('backImg', function(value) {
            element.css({
                'background': 'transparent url(' + value +')'
            });
        });
    };
});

and then use it in your template like this:

<div ng-if="vis" class="container" back-img="{{imgSrc}}"></div>

I have updated your fiddle and it seems to work fine http://jsfiddle.net/dS4pB/3/

Upvotes: 12

Related Questions