web-dev-qa-db-fra.com

angularjs: ng-src équivalent pour background-image: url (...)

Dans angularjs, vous avez le tag ng-src qui a pour but de ne pas recevoir d'erreur pour une URL invalide avant qu'angularjs n'ait à évaluer les variables placées entre {{ et }}.

Le problème est que j'utilise pas mal de DIV avec un background-image défini sur une URL. Je le fais en raison de l'excellente propriété CSS3 background-size qui recadre l'image à la taille exacte de la DIV.

Le seul problème est que je reçois beaucoup d'erreurs pour la même raison, ils ont créé une balise ng-src: j'ai des variables dans l'URL et le navigateur pense que l'image n'existe pas.

Je me rends compte qu'il est possible d'écrire un {{"style='background-image:url(myVariableUrl)'"}} brut, mais cela semble «sale».

J'ai beaucoup cherché et je ne trouve pas la bonne façon de procéder. Mon application est en train de devenir un gâchis à cause de toutes ces erreurs.

148
Jasper Schulte

ngSrc est une directive native, il semble donc que vous souhaitiez une directive similaire modifiant le style background-image de votre div. 

Vous pouvez écrire votre propre directive qui fait exactement ce que vous voulez. Par exemple

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

Que vous invoqueriez comme ceci

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

JSFiddle avec des chats mignons en bonus: http://jsfiddle.net/jaimem/aSjwk/1/

197
jaime

Celui-ci fonctionne pour moi

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

La réponse ci-dessus ne prend pas en charge l'interpolation observable (et me coûte beaucoup de temps pour essayer de déboguer). Le commentaire jsFiddle in @BrandonTilley était la réponse qui a bien fonctionné pour moi, et que je vais publier à nouveau ici pour la préservation:

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

Exemple utilisant un contrôleur et un modèle

Manette :

$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];

Modèle :

Utilisez dans le modèle comme suit:

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

ou comme si:

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

Il est également possible de faire quelque chose comme ceci avec ng-style:

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

qui ne chercherait pas à récupérer une image non existante.

40

Similaire à la réponse de hooblei, juste avec interpolation:

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

juste une question de goût mais si vous préférez accéder à la variable ou à la fonction directement comme ceci:

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

au lieu d'interpoler comme ceci: 

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

alors vous pouvez définir la directive un peu différemment avec scope.$watch qui fera $parse sur l'attribut

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'
            });
        });
    };
})

ici: AngularJS: Différence entre les méthodes $ observe et $ watch

9
kristok

@jaime ta réponse est très bien. Mais si votre page a le $ http.get alors vous avez utiliser ng-if

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

dans l'usine

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

dans la zone du contrôleur

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
        };
    });
});

et la vue si vous utilisez ng-if comme ci-dessous, vous obtiendrez l'image par interpolation, sinon, vous ne pourrez pas obtenir l'image car directive donne la valeur avant la requête HTTP.

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

J'ai trouvé avec 1.5 composants que l'abstraction du style dans le DOM était plus efficace dans une situation asynchrone.

Exemple:

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

Et dans le contrôleur, quelque chose aime ça:

this.$onChanges = onChanges;

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

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

Puisque vous avez mentionné ng-src et qu'il semble que vous souhaitiez que la page termine le rendu avant de charger votre image, vous pouvez modifier la réponse de jaime pour exécuter la directive native après le navigateur termine le rendu.

Cet article de blog explique cela plutôt bien; En gros, vous insérez le $timeout wrapper pour window.setTimeout avant la fonction de rappel dans laquelle vous apportez ces modifications au CSS.

0
aralar