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

150

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

Le problème est que j'utilise pas mal de DIV avec un background-imageensemble à une URL. Je fais cela en raison de l'excellente propriété CSS3 background-sizequi recadre l'image à la taille exacte du DIV.

Le seul problème est que je reçois beaucoup d'erreurs pour la même raison pour laquelle 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 y a une possibilité d'écrire un brut {{"style='background-image:url(myVariableUrl)'"}}, mais cela semble «sale».

J'ai beaucoup cherché et je ne trouve pas la bonne façon de faire. Mon application devient un désordre à cause de toutes ces erreurs.

Jasper Schulte
la source

Réponses:

200

ngSrcest une directive native, il semble donc que vous souhaitiez une directive similaire qui modifie le background-imagestyle de votre div .

Vous pouvez rédiger 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'
        });
    };
});​

Ce que tu invoquerais comme ça

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

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

jaime
la source
67
Très belle directive; le seul problème est qu'il ne prend pas en charge l'interpolation. Je le modifierais probablement ainsi: jsfiddle.net/BinaryMuse/aSjwk/2
Michelle Tilley
1
Merci, peu importe que ce soit sans interpolation, il a des chatons!
Visgean Skeloru
Des problèmes de sécurité avec cela si vous chargez à partir de sources non fiables?
Aakil Fernandes
cela fonctionne, mais seulement si l'url de votre image est déjà définie, utilisez la réponse @mythz stackoverflow.com/a/15537359/1479680 pour avoir une meilleure URL obeservable
Magico
229

Celui-ci fonctionne pour moi

<li ng-style="{'background-image':'url(/static/'+imgURL+')'}">...</li>
hooblei
la source
22
Je pense que cela devrait être la réponse acceptée. Il n'est pas nécessaire d'ajouter une directive personnalisée.
Jakob Løkke Madsen
2
J'ai ajouté une réponse similaire à celle-là, en utilisant simplement l'interpolation
wiherek
1
C'est plus sale, dans le sens où une directive convient à tout, partout où vous avez besoin d'un arrière-plan dynamique. La question mentionnait qu'elle se sentait moins réutilisable.
Christian Bonato
Ne fonctionne pas dans Angular 1.5.8, il essaie toujours de charger l'image avec imgURLnon défini et réessaye une fois imgURLdéfini.
leroydev
Ceci est incorrect, si vous avez des variables spéciales comme @% dans votre URL, cela se cassera.
efwjames
69

La réponse ci-dessus ne prend pas en charge l'interpolation observable (et m'a coûté beaucoup de temps à essayer de déboguer). Le lien jsFiddle dans le commentaire @BrandonTilley était la réponse qui a fonctionné pour moi, que je re-posterai 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 ceci:

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

ou comme ça:

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

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

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

qui n'essaierait pas de récupérer une image inexistante.

principe holographique
la source
2
@sqren voyez également ceci si vous utilisez une version plus récente d'Angular (1.1.5 et plus): stackoverflow.com/a/12151492/1218080 . La prise en charge d'un opérateur ternaire réel dans les vues a été ajoutée.
principe holographique
une simple concaténation de chaînes comme celle-ci a fonctionné pour moi sur l'objet scope, au lieu de l'interpolation.
Shardul
25

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

<li ng-style="{'background-image': 'url({{ image.source }})'}">...</li>
wiherek
la source
1
Il ne fonctionne pas ici: <span ng-style="{'background-image': 'url(/styles/images/profile.png)'}" style="background-image: url("");"></span>. L'approche @hooblei a fonctionné.
Marcos Lima
Obtenir le même résultat :(
Kushal Jayswal
9

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.$watchce qui fera $parsesur 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'
            });
        });
    };
})

il y a plus de détails à ce sujet ici: AngularJS: Différence entre les méthodes $ observe et $ watch

Kristok
la source
2

@jaime votre réponse est très bien. Mais si votre page a le $ http.get, vous devez 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 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 le ng-if comme ci-dessous, vous obtiendrez l'image par interpolation sinon, vous ne pouvez pas obtenir l'image car la directive obtient la valeur avant la requête HTTP.

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

J'ai trouvé avec 1.5 composants qui résumaient le style du DOM pour fonctionner le mieux dans ma situation asynchrone.

Exemple:

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

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

this.$onChanges = onChanges;

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

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

Puisque vous l'avez mentionné ng-srcet qu'il semble que vous vouliez que la page finisse le rendu avant de charger votre image, vous pouvez modifier la réponse de jaime pour exécuter la directive native une fois le rendu du navigateur terminé.

Ce billet de blog explique assez bien cela; essentiellement, vous insérez l' $timeoutenveloppe pour window.setTimeoutavant que la fonction de rappel dans laquelle vous faites ces modifications au CSS.

Aralar
la source