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.

Answers


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


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/


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


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.


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

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

Need Your Help

XPath selection by innertext

xml xpath

I'm trying to extract an element with a particular innertext from a parsed XML document. I know that I can select an element that has a child with a particular innertext using //myparent[mychild='...

How does MatchEvaluator in Regex.Replace work?

c# .net regex replace matchevaluator

This is the input string 23x * y34x2. I want to insert " * " (star surrounded by whitespaces) after every number followed by letter, and after every letter followed by number. So my input string wo...