Как изменить AngularJS ng-src, когда API возвращает нулевое значение?

StackOverflow https://stackoverflow.com//questions/20007112

Вопрос

При работе с API с сайта themoviedb.com я ввожу пользователя в поле ввода, отправляя запрос API при каждом нажатии клавиши.При тестировании иногда постер фильма имел значение «null» вместо предполагаемого «poster_path».Я предпочитаю по умолчанию использовать изображение-заполнитель, чтобы указать, что плакат не был найден по запросу API.

Итак, поскольку API-интерфейс не предлагает весь URL-адрес poster_path, и поскольку я использую ng-повтор AngularJS, мне приходится структурировать тег изображения следующим образом (используя фиктивные данные для экономии места):

<img ng-src="{{'http://example.com/'+movie.poster_path}}" alt="">

Но затем консоль выдает ошибку из-за неправильного запроса, поскольку не возвращается полный путь к изображению.Я попробовал использовать подсказку OR:

{{'http://example.com/'+movie.poster_path || 'http://example.com/missing.jpg'}}

Но в данном случае это не работает.Итак, теперь с javascript.Кажется, я не могу получить источник изображения, используя getElementsByTagName или getElementByClass, а использование getElementById, похоже, захватывает только первое повторение и ничего больше, что, как я полагал, будет иметь место.Но даже тогда я не могу заменить источник изображения.Вот структура кода, которую я попробовал:

<input type="text" id="search">
<section ng-controller="movieSearch">
  <article ng-repeat="movie in movies">
    <img id="myImage" src="{{'http://example.com/'+movie.poster_path}}" alt="">
  </article>
</section>

<script>
function movieSearch($scope, $http){
  var string,
      replaced,
      imgSrc,
      ext,
      missing;

  $(document).on('keyup', function(){
    string = document.getElementById('search').value.toLowerCase();
    replaced = string.replace(/\s+/g, '+');
    $http.jsonp('http://example.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
      console.dir(data.results);
      $scope.movies = data.results;
    });
    imgSrc = document.getElementById('myImage').src;
    ext = imgSrc.split('.').pop();
    missing='http://example.com/missing.jpg';
    if(ext !== 'jpg'){
      imgSrc = missing;
    }
  });
}
</script>

Есть какие-нибудь идеи относительно того, что я делаю неправильно, и можно ли вообще сделать то, что я пытаюсь сделать?

Это было полезно?

Решение

Первая проблема, которую я вижу, заключается в том, что пока вы устанавливаете movies в асинхронном обратном вызове вы синхронно ищете источник изображения здесь:

$http.jsonp('http://domain.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
  console.dir(data.results);
  $scope.movies = data.results;
}); 

// This code will be executed before `movies` is populated

imgSrc = document.getElementById('myImage').src;
ext = img.split('.').pop();

Однако перемещение кода просто в обратный вызов не решит проблему:

// THIS WILL NOT FIX THE PROBLEM

$http.jsonp('http://domain.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
  console.dir(data.results);
  $scope.movies = data.results;

    // This will not solve the issue

    imgSrc = document.getElementById('myImage').src;
    ext = img.split('.').pop();
    // ...
}); 

Это потому, что src поля будут заполнены только в следующем цикл дайджеста.

В вашем случае вам следует обрезать результаты, как только вы получите их от обратного вызова JSONP:

function movieSearch($scope, $http, $timeout){
  var string,
      replaced,
      imgSrc,
      ext,
      missing;

  $(document).on('keyup', function(){
    string = document.getElementById('search').value.toLowerCase();
    replaced = string.replace(/\s+/g, '+');
    $http.jsonp('http://domain.com/query='+replaced+'&callback=JSON_CALLBACK').success(function(data) {
      console.dir(data.results);
      $scope.movies = data.results;

      $scope.movies.forEach(function (movie) {
        var ext = movie.poster_path && movie.poster_path.split('.').pop();

        // Assuming that the extension cannot be
        // anything other than a jpg
        if (ext !== 'jpg') {
            movie.poster_path = 'missing.jpg';
        }
      });
    });
  });
}

Здесь вы изменяете только model просматривайте за собой и не делайте никакого последующего анализа DOM, чтобы выявить сбои.


Примечание: Вы могли бы использовать тернарный оператор для решения проблемы в представлении, но это не рекомендуется:

<!-- NOT RECOMMENDED -->
{{movie.poster_path && ('http://domain.com/'+movie.poster_path) || 'http://domain.com/missing.jpg'}}

Другие советы

Во-первых, я определил фильтр, как это:

в CoffeeScript:

app.filter 'cond', () ->
    (default_value, condition, value) ->
        if condition then value else default_value
.

или в JavaScript:

  app.filter('cond', function() {
    return function(default_value, condition, value) {
      if (condition) {
        return value;
      } else {
        return default_value;
      }
    };
  });
.

Тогда вы можете использовать это так:

{{'http://domain.com/missing.jpg' |cond:movie.poster_path:('http://domain.com/'+movie.poster_path)}}
.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top