angularjs: ng-src equivalent for background-image:url(...)

CssAngularjs

Css Problem Overview


In angularjs you have the tag ng-src which has the purpose that you won't receive an error for an invalid url before angularjs gets to evaluate the variables placed in between {{ and }}.

The problem is that I use quite some DIV's with a background-image set to an url. I do this because of the excellent CSS3 property background-size which crops the image to the exact size of the DIV.

The only problem is that I receive a lot of errors for the exact same reason they created a ng-src tag: I have some variables in the url and the browser thinks the image doesn't exist.

I realize that there is a possibility of writing a crude {{"style='background-image:url(myVariableUrl)'"}}, but this seems 'dirty'.

I've searched a lot and can't find the right way to do this. My app is becoming a mess because of all of these errors.

Css Solutions


Solution 1 - Css

This one works for me

<li ng-style="{'background-image':'url(/static/'+imgURL+')'}">...</li>

Solution 2 - Css

ngSrc is a native directive, so it seems you want a similar directive that modifies your div's background-image style.

You could write your own directive that does exactly what you want. For example

app.directive('backImg', function(){
    return function(scope, element, attrs){
        var url = attrs.backImg;
        element.css({
            'background-image': 'url(' + url +')',
            'background-size' : 'cover'
        });
    };
});​

Which you would invoke like this

<div back-img="<some-image-url>" ></div>

JSFiddle with cute cats as a bonus: http://jsfiddle.net/jaimem/aSjwk/1/

Solution 3 - Css

The above answer doesn't support observable interpolation (and cost me a lot of time trying to debug). The jsFiddle link in @BrandonTilley comment was the answer that worked for me, which I'll re-post here for preservation:

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

Example using controller and template

Controller :

$scope.someID = ...;
/* 
The advantage of using directive will also work inside an ng-repeat :
someID can be inside an array of ID's 
*/

$scope.arrayOfIDs = [0,1,2,3];

Template :

Use in template like so :

<div back-img="img/service-sliders/{{someID}}/1.jpg"></div>

or like so :

<div ng-repeat="someID in arrayOfIDs" back-img="img/service-sliders/{{someID}}/1.jpg"></div>

Solution 4 - Css

It's also possible to do something like this with ng-style:

ng-style="image_path != '' && {'background-image':'url('+image_path+')'}"

which would not attempt to fetch a non-existing image.

Solution 5 - Css

Similar to hooblei's answer, just with interpolation:

<li ng-style="{'background-image': 'url({{ image.source }})'}">...</li>

Solution 6 - Css

just a matter of taste but if you prefer accessing the variable or function directly like this:

<div id="playlist-icon" back-img="playlist.icon">

instead of interpolating like this:

<div id="playlist-icon" back-img="{{playlist.icon}}">

then you can define the directive a bit differently with scope.$watch which will do $parse on the attribute

angular.module('myApp', [])
.directive('bgImage', function(){

    return function(scope, element, attrs) {
	    scope.$watch(attrs.bgImage, function(value) {
		    element.css({
			    'background-image': 'url(' + value +')',
			    'background-size' : 'cover'
		    });
	    });
    };
})

there is more background on this here: https://stackoverflow.com/questions/14876112/difference-between-the-observe-and-watch-methods

Solution 7 - Css

@jaime your answer is fine. But if your page has the $http.get then you have use ng-if

app.directive('backImg', function(){
	return function($scope, $element, $attrs){
		var url = $attrs.backImg;
		$element.css({
			'background-image': 'url(' + url + ')',
			'background-size': 'cover'
		});
	}
});

in the factory

app.factory('dataFactory', function($http){
    var factory = {};
    factory.getAboutData = function(){
        return $http.get("api/about-data.json");
    };
    return factory;
});

in the controller area

app.controller('aboutCtrl', function($scope, $http, dataFactory){
	$scope.aboutData = [];
	dataFactory.getAboutData().then(function(response){
		// get full home data
		$scope.aboutData = response.data;
		// banner data
		$scope.banner = {
			"image": $scope.aboutData.bannerImage,
			"text": $scope.aboutData.bannerText
		};
	});
});

and the view if you use the ng-if like below then you will get the image by interpolation otherwise, you can't get the image because directive get the value before HTTP request.

<div class="stat-banner"  ng-if="banner.image" background-image-directive="{{banner.image}}">

Solution 8 - Css

I've found with 1.5 components that abstracting the styling from the DOM to work best in my async situation.

Example:

<div ng-style="{ 'background': $ctrl.backgroundUrl }"></div>

And in the controller, something likes this:

this.$onChanges = onChanges;
	
function onChanges(changes) {
	if (changes.value.currentValue){
		$ctrl.backgroundUrl = setBackgroundUrl(changes.value.currentValue);
	}
}

function setBackgroundUrl(value){
	return 'url(' + value.imgUrl + ')';
}

Solution 9 - Css

Since you mentioned ng-src and it seems as though you want the page to finish rendering before loading your image, you may modify jaime's answer to run the native directive after the browser finishes rendering.

This blog post explains this pretty well; essentially, you insert the $timeout wrapper for window.setTimeout before the callback function wherein you make those modifications to the CSS.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasper SchulteView Question on Stackoverflow
Solution 1 - CsshoobleiView Answer on Stackoverflow
Solution 2 - CssjaimeView Answer on Stackoverflow
Solution 3 - CssmythzView Answer on Stackoverflow
Solution 4 - Cssholographic-principleView Answer on Stackoverflow
Solution 5 - CsswiherekView Answer on Stackoverflow
Solution 6 - CsskristokView Answer on Stackoverflow
Solution 7 - CssSubhojit MondalView Answer on Stackoverflow
Solution 8 - CssPat MigliaccioView Answer on Stackoverflow
Solution 9 - CssaralarView Answer on Stackoverflow