使用JavaScript(TMD.js)将流派ID与流派名称匹配 [英] Matching genre ids with genre names in TMDb with JavaScript (Ember.js)

查看:103
本文介绍了使用JavaScript(TMD.js)将流派ID与流派名称匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我敢肯定,你们中的很多人已经使用了TMDb(电影数据库)API来拍摄电影。但是我在显示每部电影的流派名称时遇到问题。我试图将电影 API中的 genre_ids 中的每个数字替换为相应的名称来自流派 api,因为向用户显示数字并不能说太多!但是我没有得到理想的结果。我不确定正确的方法是什么...

I'm sure a lot of you have used the TMDb (The Movie Database) api for movies. But I'm having issues with showing the genre names for each movie displayed. I'm trying to replace each number in genre_ids, from movies api, with their corresponding name from genres api, as showing numbers to users doesn't say much! But I don't get the desired result. I'm not sure what the correct way is...

电影适配器

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;
  }),
});

Movies API (每个电影的结果数组具有以下结构):

Movies API (each movie from the results array has this structure):

{
  "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}}

推荐答案

我认为您的主要问题是您试图修复组件层上的某些问题,而这些问题最好在模型层上进行处理。
当您可以做到这一点时,您真正想要的是从电影模型到类型的关系模型:

I think your primary problem is that you're trying to fix something on the component layer that is better handled on the model layer. While you can do that, what you actually want is a relationship from the movie model to the genre model:

genres: hasMany('genre'),

我不确定您的API提供了1:1的内容,因为您尚未粘贴 exact 响应。在某些时候,您提到了 results 数组,并且流派似乎包裹在流派数组中。因此,如果那不是100%正确,那么您可能需要稍微调整一下此解决方案。

I'm not sure what your API provides 1:1 because you've not pasted the exact response. At some point you've mentioned a results array, and the genres seems to be wrapped inside a genres array. So if thats not 100% correct you maybe need to tweak this solution a bit.

首先,我会推荐较新的 JSONSerializer 而不是 RESTSerializer

For the start I would recommend the newer JSONSerializer instead of the RESTSerializer.

现在您需要告诉余烬了类型关系,则应使用 genre_ids 数组中提供的ID。这可以通过 keyForRelationship

Now you need to tell ember that for the genres relationship it should use the ids provided in the genre_ids array. This can be done by 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->体裁),然后只需添加 _ids 。这足以使余烬识别id,然后使用它们提供正确的模型实例。

Here I use the ember-inflector to get the singular of the relationship name (so genres -> genre) and then just add _ids. This is enough for ember to recognize the ids and then use them to provide the right model instances.

接下来,您基本上可以循环遍历流派在您的电影型号上:

Next you can basically just loop over genres on your movie model:

{{#each movie.genres as |genre|}}
  {{genre.name}}
{{/each}}

现在,您甚至不需要将所有类型的列表传递给控制器​​/模板。但是,您仍然需要加载,以便 ember-data 可以使用它们。否则 ember-data 会在您使用它们时尝试分别获取它们。

Now you don't even need to pass the list of all genres to the controller/template. However you still need to load them so ember-data can use them. Otherwise ember-data would try to fetch them individually when you use them.

所以您的 model 钩子可能看起来像这样:

So your model hook could look like this:

model() {
  return RSVP.hash({
    genres: this.store.findAll('genre'),
    movies: this.store.findAll('movie'),
  }).then(x => x.movies);
}

这是实现此目的的一种麻烦方式。但是,由于我不想实时获取数据,因此我创建了返回静态数据的虚拟适配器。

Here is a twiddle implementing this. However because I don't wanted to live-fetch the data I've created dummy adapters that return static data.

这篇关于使用JavaScript(TMD.js)将流派ID与流派名称匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆