49

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.

5 Answers 5

93

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

Sign up to request clarification or add additional context in comments.

2 Comments

I think its normal its about watcher which's not applying deep watch in this case.
example : backgroundColor is still the same even if its value changes, but if you add color property it will be applied because a new property on the first level is added.
12

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/

Comments

6

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

3 Comments

I tried the timeout, however it did not fix the issue ... I even tried a 10 sec delay, then inspected the element. after 10 sec the ng-style attribute updated however the view stayed the same. any new idea?
This works perfectly. Because of the way timeout works you actually don't even need to put any time delay in at all. Thanks!
Thanks, there are tears of joy running down my cheeks.
1

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.

Comments

-1

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

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

2 Comments

@RPDeshaies Maybe, but as Angular 2 gains more of a following, this question will still potentially be top google result for people looking for these answers on the new framework
@S.Buda no because angular 2+ has no ng-style I'm here for legacyjs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.