Я уверен, что многие из вас использовали API TMDb (База данных фильмов) для фильмов. Но у меня возникают проблемы с отображением названий жанров для каждого отображаемого фильма. Я пытаюсь заменить каждый номер в genre_ids из фильмы api на их соответствующий name из жанры api, так как отображение чисел для пользователей мало что говорит! Но не получаю желаемого результата. Я не уверен, каков правильный путь ...
Видеоадаптер
import DS from 'ember-data';
const apiKey = 'SOME_API_KEY_HERE';
export default DS.RESTAdapter.extend({
host: `https://api.themoviedb.org/`,
namespace: '3',
pathForType() {
return `discover/movie?sort_by=popularity.desc&api_key=${apiKey}`;
},
});
Жанровый адаптер
import DS from 'ember-data';
const apiKey = 'SOME_API_KEY_HERE';
export default DS.RESTAdapter.extend({
host: `https://api.themoviedb.org/`,
namespace: '3',
pathForType() {
return `genre/movie/list?api_key=${apiKey}`;
},
});
Сериализатор фильмов
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
payload = { movies: payload.results };
return this._super(store, primaryModelClass, payload, id, requestType);
}
});
Жанровый сериализатор
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
payload = { genres: payload.genres };
return this._super(...arguments);
}
});
Модель фильма
import DS from 'ember-data';
const { attr, hasMany } = DS;
export default DS.Model.extend({
vote_count: attr('number'),
video: attr('boolean'),
vote_average: attr('number'),
title: attr('string'),
popularity: attr('number'),
poster_path: attr('string'),
original_language: attr('string'),
original_title: attr('string'),
genre_ids: attr(),
backdrop_path: attr('string'),
adult: attr('boolean'),
overview: attr('string'),
release_date: attr('date'),
});
Жанровая модель
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
});
Маршрут
import Route from '@ember/routing/route';
import RSVP from 'rsvp'
export default Route.extend({
model() {
return RSVP.hash({
movies: this.store.findAll('movie'),
genres: this.store.findAll('genre'),
});
},
});
Компонент листинга фильмов
import Component from '@ember/component';
import { computed } from '@ember/object';
export default Component.extend({
movieGenreIds: computed('[email protected]_ids', function() {
return this.movies.map(movie => movie.genre_ids).reduce((a, b) => [...a, ...b]);
}),
genresNames: computed('movieGenreIds', 'genres', 'movies', function() {
let names = [];
this.genres.map((genre) => {
this.movieGenreIds.forEach(movieGenreId => {
if (parseInt(genre.id) === movieGenreId) {
names.push(genre.name);
}
})
})
return names;
}),
});
API фильмов (каждый фильм из массива results имеет такую структуру):
{
"vote_count": 1092,
"id":335983,
"video": false,
"vote_average": 6.7,
"title": "Venom",
"popularity": 505.173,
"poster_path": "/2uNW4WbgBXL25BAbXGLnLqX71Sw.jpg",
"original_language": "en",
"original_title": "Venom",
"genre_ids": [27,878,28,53,35], // <-- I'm interested in this property
"backdrop_path": "/VuukZLgaCrho2Ar8Scl9HtV3yD.jpg",
"adult": false,
"overview": "When Eddie Brock acquires the powers of a symbiote, he will have to release his alter-ego “Venom” to save his life.",
"release_date": "2018-10-03"
}
Жанры API
"genres":[
{"id":28,"name":"Action"},
{"id":12,"name":"Adventure"},
{"id":16,"name":"Animation"},
{"id":35,"name":"Comedy"},
...
]
Шаблон Hbs (ожидаемый результат)
<ul class = "movie">
{{#each movies as |movie|}}
<li>
<h2 class = "movie__title">{{movie.title}}</h2>
<p class = "movie__genre">
genres:
{{#each genresNames as |genre|}}
{{genre}} <!-- a list of genre names for this particular movie -->
{{/each}}
</p>
<img src = "https://image.tmdb.org/t/p/w500/{{movie.poster_path}}" alt = "" class = "movie__image">
</li>
{{/each}}
@barbsan, спасибо за ответ! В основном я хочу заменить числа в массиве genre_ids на их соответствующее «имя», чтобы я мог показать их в браузере. Потому что отображение чисел мало что говорит!
Возможно, попробуйте так: Получение названия жанра, соответствующего идентификатору жанра, и получение названий актеров
Конечно, но я спрашиваю о структуре этого ожидаемого результата, а не о том, почему вы это делаете. Для того, что я вижу, вы создаете массив всех жанров без информации о муравье фильма, тогда вы пытаетесь создать массив имен жанров, соответствующих этим первым идентификаторам массива (снова без идентификатора фильма)
Дело в том, что я пробовал много способов, поэтому приведенный выше код Ember был лишь последней попыткой, которую я сделал, и я знаю, что это неверно. Вот почему я прошу новый способ, о котором еще не думал.
Вы используете ember-data? Куда и как загружать данные?
@Люкс! Да, я использую ember-data и получаю доступ к данным с route. Я добавил код ember-data. Модели имеют ту же структуру, что и json. Не хотел задавать вопрос слишком длинным, так как некоторым это не нравится, поэтому я не вставлял модели.
Пожалуйста, покажите свои модели и сериализатор. Это должно быть сделано полностью в сериализаторе!
@Люкс! Я вставил модели и сериализаторы, как просил.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, ваша основная проблема заключается в том, что вы пытаетесь исправить что-то на уровне компонентов, что лучше обрабатывается на уровне модели.
Пока вы это делаете жестяная банка, на самом деле вам нужна связь модели movie с моделью genre:
genres: hasMany('genre'),
Я не уверен, что ваш API предоставляет 1: 1, потому что вы не вставили ответ точный. В какой-то момент вы упомянули массив results, и кажется, что жанры заключены в массив genres. Так что, если это не на 100% правильно, возможно, вам нужно немного подправить это решение.
Для начала я бы порекомендовал более новый JSONSerializer вместо RESTSerializer.
Теперь вам нужно сообщить ember, что для связи genres он должен использовать идентификаторы, предоставленные в массиве genre_ids. Это можно сделать с помощью keyForRelationship:
import DS from 'ember-data';
import {singularize} from 'ember-inflector';
export default DS.JSONSerializer.extend({
...
keyForRelationship(key, typeClass, method) {
return `${singularize(key)}_ids`;
},
});
Здесь я использую ember-inflector, чтобы получить единственное число имени отношения (например, genres -> genre), а затем просто добавляю _ids. Этого достаточно, чтобы ember распознал идентификаторы, а затем использовал их для предоставления нужных экземпляров модели.
Затем вы можете просто перебрать genres на своей модели movie:
{{#each movie.genres as |genre|}}
{{genre.name}}
{{/each}}
Теперь вам даже не нужно передавать список всех жанров в контроллер / шаблон. Однако вам все равно нужно нагрузка их, чтобы ember-data мог их использовать. В противном случае ember-data будет пытаться получить их по отдельности, когда вы их используете.
Итак, ваш хук model может выглядеть так:
model() {
return RSVP.hash({
genres: this.store.findAll('genre'),
movies: this.store.findAll('movie'),
}).then(x => x.movies);
}
Вот тиддл, реализующий это. Однако, поскольку я не хотел получать данные в реальном времени, я создал фиктивные адаптеры, возвращающие статические данные.
Спасибо @Lux! Ваш ответ мне очень помог. Я изменил ваше решение, и оно работает. Спасибо за вашу большую помощь!
Собираетесь ли вы добавить к каждому объекту фильма свойство с названиями жанров? Непонятно, чего вы пытаетесь достичь (и, похоже, нет необходимости создавать массив
movieGenreIdдля этой цели)