angularjs: equivalente ng-src para background-image: url (…)

150

No angularjs, você tem a tag ng-src, que tem como objetivo não receber um erro por um URL inválido antes que o angularjs avalie as variáveis ​​colocadas entre {{e }}.

O problema é que eu uso alguns DIVs com um background-imageconjunto para um URL. Eu faço isso por causa da excelente propriedade CSS3, background-sizeque corta a imagem no tamanho exato da DIV.

O único problema é que recebo muitos erros pelo mesmo motivo pelo qual eles criaram uma marca ng-src: tenho algumas variáveis ​​no URL e o navegador acha que a imagem não existe.

Percebo que existe a possibilidade de escrever um bruto {{"style='background-image:url(myVariableUrl)'"}}, mas isso parece "sujo".

Pesquisei bastante e não consigo encontrar o caminho certo para fazer isso. Meu aplicativo está se tornando uma bagunça por causa de todos esses erros.

Jasper Schulte
fonte

Respostas:

200

ngSrcé uma diretiva nativa, portanto, parece que você deseja uma diretiva semelhante que modifique o background-imageestilo da sua div .

Você pode escrever sua própria diretiva que faz exatamente o que você deseja. Por exemplo

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

Que você chamaria assim

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

JSFiddle com gatos fofos como um bônus: http://jsfiddle.net/jaimem/aSjwk/1/

jaime
fonte
67
Diretiva muito boa; o único problema é que ele não suporta interpolação. Eu provavelmente iria modificá-lo assim: jsfiddle.net/BinaryMuse/aSjwk/2
Michelle Tilley
1
Obrigado, não importa se é sem interpolação, tem gatinhos!
Visgean Skeloru
Algum problema de segurança com isso, se você estiver carregando de fontes não confiáveis?
Aakil Fernandes
Isso funciona, mas apenas se sua imagem url já está definido, a resposta uso @mythz stackoverflow.com/a/15537359/1479680 ter uma url melhor obeservable
Magico
229

Este funciona para mim

<li ng-style="{'background-image':'url(/static/'+imgURL+')'}">...</li>
hooblei
fonte
22
Eu acho que essa deve ser a resposta aceita. Não há necessidade de adicionar uma diretiva personalizada.
Jakob Løkke Madsen
2
Eu adicionei uma resposta semelhante a esse, apenas usando interpolação
wiherek
1
É mais sujo, no sentido de que uma diretiva serve para todos, em todos os lugares em que você precisa de um plano de fundo dinâmico. A pergunta mencionada parecia menos reutilizável.
Christian Bonato
Não funciona no Angular 1.5.8, ainda tenta carregar a imagem com imgURLnão definido e tenta novamente quando imgURLé definido.
leroydev 16/09/16
Isso está incorreto. Se você tiver variáveis ​​especiais como @% no seu URL, ele será interrompido.
Efwjames 28/09/16
69

A resposta acima não suporta interpolação observável (e me custou muito tempo tentando depurar). O link do jsFiddle no comentário do @BrandonTilley foi a resposta que funcionou para mim, que postarei novamente aqui para preservação:

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

Exemplo usando controlador e modelo

Controlador:

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

Predefinição:

Use no modelo assim:

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

ou assim:

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

Também é possível fazer algo assim com ng-style:

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

que não tentaria buscar uma imagem inexistente.

princípio holográfico
fonte
2
O @sqren também vê isso se você estiver usando uma versão mais recente do Angular (1.1.5 e superior): stackoverflow.com/a/12151492/1218080 . Foi adicionado suporte para um operador ternário real em visualizações.
princípio holográfico
uma concatenação simples de string como essa funcionou para mim no objeto de escopo, em vez de interpolação.
Shardul 13/08/2015
25

Semelhante à resposta de hooblei, apenas com interpolação:

<li ng-style="{'background-image': 'url({{ image.source }})'}">...</li>
wiherek
fonte
1
Não funcionou aqui: <span ng-style="{'background-image': 'url(/styles/images/profile.png)'}" style="background-image: url("");"></span>. abordagem @hooblei funcionou.
Marcos Lima
Obtendo o mesmo resultado :(
Kushal Jayswal 24/01
9

apenas uma questão de gosto, mas se você preferir acessar a variável ou função diretamente assim:

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

em vez de interpolar assim:

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

então você pode definir a diretiva de maneira um pouco diferente da scope.$watchque será feita $parseno atributo

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

há mais informações sobre isso aqui: AngularJS: Diferença entre os métodos $ observe e $ watch

kristok
fonte
2

@jaime sua resposta está bem. Mas se a sua página tiver o $ http.get, 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'
        });
    }
});

na fábrica

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

na área do controlador

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

e a visualização, se você usar o ng-if como abaixo, obterá a imagem por interpolação, caso contrário, não poderá obtê-la porque a diretiva obterá o valor antes da solicitação HTTP.

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

Descobri com 1,5 componentes que abstrair o estilo do DOM para funcionar melhor em minha situação assíncrona.

Exemplo:

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

E no controlador, algo assim:

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
fonte
0

Como você mencionou ng-srce parece que deseja que a página termine de renderizar antes de carregar sua imagem, você pode modificar a resposta do jaime para executar a diretiva nativa depois que o navegador terminar a renderização.

Esta postagem no blog explica isso muito bem; essencialmente, inserir o $timeoutinvólucro para window.setTimeoutantes da função de retorno de chamada que você faz essas modificações para o CSS.

aralar
fonte