EmberJS使用ember-data-url-templates定制适配器

bsm*_*drs 5 javascript ember.js ember-data-url-templates

我再次与EmberJS中的适配器挣扎.这次它与使用ember-data-url-templates的嵌套api请求有关.

首先,相关代码:

// /app/application/adapter.js
import DS from 'ember-data';

var AppAdapter = DS.JSONAPIAdapter.extend({
    host: 'http://coursedev.api'
});

export default AppAdapter;

// /app/router.js
import Ember from 'ember';
import config from './config/environment';

const Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.route('courses');
  this.route('course', { path: '/course/:course_id' });
  this.route('lesson', { path: '/course/:course_id/lesson/:lesson_id' });
});

export default Router;

// app/course/model.js
import DS from 'ember-data';

export default DS.Model.extend({
    order: DS.attr('number'),
    title: DS.attr('string'),
    body: DS.attr('string'),
    lessons: DS.hasMany('lesson')
});

// app/lesson/model.js
import DS from 'ember-data';

export default DS.Model.extend({
    order: DS.attr('number'),
    title: DS.attr('string'),
    body: DS.attr('string'),
    course: DS.belongsTo('course'),
    questions: DS.hasMany('question')
});

// app/lesson/adapter.js
import AppAdapter from '../application/adapter';
import UrlTemplates from "ember-data-url-templates";

export default AppAdapter.extend(UrlTemplates, {
    urlTemplate: '{+host}/courses/{courseId}/lesson/{id}',

    urlSegments: {
        host: function () { 
            return this.get('host'); 
        },
        courseId: function(type, id, snapshot, query) {
            return snapshot.belongsTo('course', { id: true });
        }
    }
});

// app/lesson/route.js
import Ember from 'ember';

export default Ember.Route.extend({
    model(params) {
        return this.store.findRecord('lesson', params.lesson_id );
    }
});

// app/lesson/template.hbs
<h1>{{model.title}}</h1>

{{model.body}}
<br>
This lesson is part of {{#link-to 'course' model.course.id}}{{model.course.title}}{{/link-to}}
Run Code Online (Sandbox Code Playgroud)

这个想法是一个课程包含几个问题.api以嵌套方式提供数据:

/courses > all the courses
/courses/{courseId} > detailed course info
/courses/{courseId}/lesson/{lessonId}/ > detailed lesson info
Run Code Online (Sandbox Code Playgroud)

在应用程序"内部"导航时,此代码工作正常,而不是直接访问路径.然后它显示适当的标题,正文以及它所属的课程.但是,当直接导航到/ courses/1/lesson/3时,适配器无法从快照中找到courseId,因为请求指向http://coursedev.api/courses//lesson/3.注意缺少courseId.此URL不存在,因为应提供courseId.

我的第一个问题是,处理嵌套api url的方法是否正确?如果是这种情况,那么应该如何收集courseId以对api做出正确的请求?

再次感谢!

Ami*_*tin 4

好的。我理解你的困惑。

当您已经有一个包含课程的课程时,您所拥有的就可以正常工作。直接导航到课程时,您需要从 url 获取课程 ID 并以某种方式将其传递给适配器。显然没有更好的解决方案;以下是一些选项,按优先顺序排列:

1. 不要在 API 中使用嵌套 url

如果您可以控制 API 的结构,我建议不要以这种方式嵌套资源。以嵌套方式加载集合子资源可能有意义(例如/courses/:course_id/lessons),但/lessions/:lesson_id优于/courses/:course_id/lessons/:lesson_id

但是,您可能无法控制您的 API,这正是创建 ember-data-url-templates 的原因......

2.使用查询记录

您可以使用它queryRecord来加载一条记录并传递更多信息,而不仅仅是一个 ID。

// adapter
export default AppAdapter.extend(UrlTemplates, {
  queryRecordUrlTemplate: '{+host}/courses/{course_id}/lesson/{lesson_id}',
});

// route
this.store.queryRecord('lesson', params);
Run Code Online (Sandbox Code Playgroud)

3. 使用服务

将信息传递给适配器的另一种方法是使用服务。这种方法看起来不适合您的情况,但我会将其包含在此处,以防它有助于解决另一个类似问题。我经常使用服务来保存一般会话信息(例如用户 ID)。以下是如何使用会话服务完成与上述相同的事情:

// adapter
export default AppAdapter.extend(UrlTemplates, {
  session: Ember.inject.service(),
  findUrlTemplate: '{+host}/courses/{courseId}/lesson/{id}',

  urlSegments: {
    courseId() { return this.get('session.courseId'); },
  },
});

// somewhere else in your application
this.set('session.courseId', params.course_id);

// route model hook
this.store.findRecord('lesson', params.lesson_id);
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助 :)