使用 JavaScript (Ember.js) 将 TMDb 中的流派 ID 与流派名称匹配
Matching genre ids with genre names in TMDb with JavaScript (Ember.js)
我相信你们中的很多人都使用过电影数据库 (TMDb) api。但是我在显示每部电影的流派名称时遇到了问题。我正在尝试用 genres[=] 中对应的 name
替换 movies api 中的每个数字65=] 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('movies.@each.genre_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}}
我认为您的主要问题是您试图在组件层上修复一些在模型层上处理得更好的东西。
虽然您 可以 这样做,但您真正想要的是从 movie
模型到 genre
模型的关系:
genres: hasMany('genre'),
我不确定您的 API 提供了什么 1:1 因为您没有粘贴 准确的 响应。在某些时候,您提到了 results
数组,并且流派似乎包含在 genres
数组中。因此,如果那不是 100% 正确,您可能需要稍微调整一下这个解决方案。
首先,我会推荐较新的 JSONSerializer
而不是 RESTSerializer
。
现在您需要告诉 ember 对于 genres
关系,它应该使用 genre_ids
数组中提供的 ID。这可以通过 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 识别 ID,然后使用它们提供正确的模型实例。
接下来,您基本上可以在 movie
模型上循环遍历 genres
:
{{#each movie.genres as |genre|}}
{{genre.name}}
{{/each}}
现在您甚至不需要将所有类型的列表传递给 controller/template。但是您仍然需要 加载 它们以便 ember-data
可以使用它们。否则 ember-data
会在您使用它们时尝试单独获取它们。
因此您的 model
挂钩可能如下所示:
model() {
return RSVP.hash({
genres: this.store.findAll('genre'),
movies: this.store.findAll('movie'),
}).then(x => x.movies);
}
Here is a twiddle implementing this。但是,因为我不想实时获取数据,所以我创建了 return 静态数据的虚拟适配器。
我相信你们中的很多人都使用过电影数据库 (TMDb) api。但是我在显示每部电影的流派名称时遇到了问题。我正在尝试用 genres[=] 中对应的 name
替换 movies api 中的每个数字65=] 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('movies.@each.genre_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}}
我认为您的主要问题是您试图在组件层上修复一些在模型层上处理得更好的东西。
虽然您 可以 这样做,但您真正想要的是从 movie
模型到 genre
模型的关系:
genres: hasMany('genre'),
我不确定您的 API 提供了什么 1:1 因为您没有粘贴 准确的 响应。在某些时候,您提到了 results
数组,并且流派似乎包含在 genres
数组中。因此,如果那不是 100% 正确,您可能需要稍微调整一下这个解决方案。
首先,我会推荐较新的 JSONSerializer
而不是 RESTSerializer
。
现在您需要告诉 ember 对于 genres
关系,它应该使用 genre_ids
数组中提供的 ID。这可以通过 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 识别 ID,然后使用它们提供正确的模型实例。
接下来,您基本上可以在 movie
模型上循环遍历 genres
:
{{#each movie.genres as |genre|}}
{{genre.name}}
{{/each}}
现在您甚至不需要将所有类型的列表传递给 controller/template。但是您仍然需要 加载 它们以便 ember-data
可以使用它们。否则 ember-data
会在您使用它们时尝试单独获取它们。
因此您的 model
挂钩可能如下所示:
model() {
return RSVP.hash({
genres: this.store.findAll('genre'),
movies: this.store.findAll('movie'),
}).then(x => x.movies);
}
Here is a twiddle implementing this。但是,因为我不想实时获取数据,所以我创建了 return 静态数据的虚拟适配器。