Как изменить AngularJS ng-src, когда API возвращает нулевое значение?
-
20-12-2019 - |
Вопрос
При работе с 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)}}
.