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.
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>
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.
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 + ')';
}
@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}}">
This one works for me
<li ng-style="{'background-image':'url(/static/'+imgURL+')'}">...</li>
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.
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: AngularJS : Difference between the $observe and $watch methods
Similar to hooblei's answer, just with interpolation:
<li ng-style="{'background-image': 'url({{ image.source }})'}">...</li>
Source: Stackoverflow.com