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.