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.

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/


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>

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>

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.


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>

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


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}}">

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

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.