Ember.JS 在组件中创建记录并添加到本地数据存储,或最佳实践解决方案

Ember.JS create record in component and add to local Datastore, or best practice solution

当前情况: 我正在尝试从组件的 "didInsertElement" 方法中找到一种方法来创建特定模型的记录,并添加所述数据到数据存储。

当前情况的原因: 我将事件侦听器附加到组件 HBS 文件中的按钮。其中一个按钮将触发两个级联但轻的 ajax 调用。最后一次 ajax 调用的响应将决定我是否应该创建记录。

我遇到的问题: 当我尝试从组件这样访问商店时:

var myStore = this.store

我得到一个未定义的对象。对于那些提问的人,我已经在我的组件中添加了以下行:

store: Ember.inject.service()

而且我已经安装了 Ember-数据。

解决方案:我从大量研究中发现,与商店的互动最好通过主路线进行。但是我如何将事件监听器从路由附加到组件的 jquery 小部件?

是否有任何解决方案不需要我将所有事件侦听器代码从组件移动到路由,从而取消 ember 应该提供的模块化?

this.store 属性 存在于默认注入它的元素上(控制器和路由)并且可能不应该被使用,因为它跳过了吸气剂,吸气剂是 Ember.

在组件中访问它的正确方法(假设你注入了它)是通过:

this.get('store')

I have found from a lot of research that interaction with the store is best done through the main route.

您可能希望(至少在大多数情况下)不在主路由中访问存储数据,而是在组件所在的控制器中访问存储数据,然后将数据传递到组件中。

这有几个原因:

  • 路由的主要用途是获取数据并控制应用程序的路由机制,用户转换到何处,转换发生的时间点以及原因等。路由不应该控制显示哪些数据以及如何显示, 只是 how/when 它获得了。
  • 控制器的主要用途是数据处理、准备、转换等。这包括过滤数据、排序数据、提取子集等。
  • 控制器数据可直接在模板中使用,而路由数据则不能。

Ember.Route 中的 setupController() 挂钩实际上默认执行此操作。

这是 the default operationsetupController() 挂钩中完成的:

set(controller, 'model', model);

因此您的控制器默认可以访问模型,然后可以将其传递给组件。

这样您就可以清楚地将 extracts/obtains/handles 数据的逻辑与显示数据的逻辑分开。

I am attaching event listeners to a button in my component HBS file. One of the buttons will trigger two cascaded but light ajax calls. The response from the last of these ajax calls will determine if I should create records or not.

在 Ember 中执行此操作的自然方法是将一个动作附加到您的按钮,该动作只会传播到控制器

// inside components/example.js
// ...
actions: {
  myButtonAction() {
    // call the controller action
    this.get('controllerActionThatWasPassedIn')(/* pass any data if necessary */);
  }
}

并让控制器执行实际的存储操作,然后在需要时将任何结果传递回组件。

// controllers/example.js
// ...
actions: {
  handleData(someArgs) {
    this.get('store)'.findSomething(someArgs).then((result) => {
      this.set('result', result); // set the result which will automatically be passed down into the component
    });
  }
}

// templates/example.hbs
{{my-component result=result
               controllerActionThatWasPassedIn=(action "handleData")
}}

在Ember中,这个概念叫做Data down, Actions up.

像这样传递的操作称为 closure actions,事实上,您也可以从它们中 return 所以这样的操作也可以工作:

// inside components/example.js
// ...
actions: {
  myButtonAction() {
    // call the controller action
    this.get('controllerActionThatWasPassedIn')(/* pass any data if necessary */)
      .then((result) => {
        // do stuff with result
      });
  }
}

How would I attach event listeners to a component's jquery widget from a route?

注:反模式

在 Ember 中并没有真正自然的方法来执行此操作,主要是因为路由和控制器是在渲染任何内容之前创建的。这就是为什么您不想在路由中而是在控制器中执行此操作的原因。

但是,如果您可能不需要控制器,只想在路由中执行一些 quick/small DOM 操作(请注意,这通常是一种反模式),您可以始终使用 Ember Run Loop 挂钩并安排一些操作在渲染后发生:

export default Ember.Route.extend({
  init() {
    this._super(...arguments);

    Ember.run.scheduleOnce('afterRender', () => {
      $('.my-component').click(/* ... */)
    });
  }
});

或者您可以直接在 renderTemplate() 挂钩中执行此操作,在呈现内容后:

renderTemplate() {
  this.render();
  $('.my-component').click(/* ... */); // Probably shouldn't do this though
}