【问题标题】:how to inject a store into a component (when using localstorage adapter)如何将存储注入组件(使用本地存储适配器时)
【发布时间】:2015-04-03 00:25:19
【问题描述】:

Ember docs说要定义一个这样的商店

MyApp.Store = DS.Store.extend();

如果您在组件中查找记录,doc 表示您可以像这样将商店注入组件中

// inject the store into all components
App.inject('component', 'store', 'store:main');

但是,我使用的是我这样定义的本地存储适配器

App.ApplicationAdapter = DS.LSAdapter.extend({ 命名空间:“我的命名空间” });

因此,我不知道如何按照上述说明将其注入组件(我需要在其中查找记录)。

按照this SO answer 的说明,我尝试通过像store=store 和/或store=controller.store 一样将store 传递到组件中

<li> {{my-component id=item.customid data=item.stats notes=item.notes store=store}} </li>

<li> {{my-component id=item.customid data=item.stats notes=item.notes store=controller.store}} </li>

目标是能够在组件中的操作中做到这一点

      var todo = this.get('store');
      console.log(todo, "the new store");
      todo.set('notes', bufferedTitle);
      console.log(todo, "todo with notes set");
      todo.save();

但是,todo.save(); 总是触发

Uncaught TypeError: undefined is not a function

注意到我登录了商店?这就是它所显示的

Class {_backburner: Backburner, typeMaps: Object, recordArrayManager: Class, _pendingSave: Array[0], _pendingFetch: ember$data$lib$system$map$$Map…}

如果我检查它(通过打开树,这里没有显示),它确实表明注释是通过todo.set('notes', bufferedTitle); 设置的,但是,它没有我模型的任何其他属性为索引路由定义,并且该对象没有“保存”方法。因此,它似乎不是实际的 store,而只是一些 backburner 对象。

我在尝试this SO answer 时得到了相同的结果,它说要获取目标对象的存储

var todo = this.get('targetObject.store');

注意,我也试过这个,即将商店设置为商品的商店。

 <li> {{my-component id=item.customid data=item.stats notes=item.notes store=item.store}} </li>

需要注意的是,如果我在组件中设置了商店,我可以通过{{store}}在页面上打印商店,这给了我

<DS.Store:ember480>

但即使在应用程序代码中,我也无法在处理点击的操作中执行var todo = this.get('store');

问题,使用 localStorage 适配器,我如何能够在组件中查找记录(目的是能够更改记录然后再次保存)

注意,如果它很重要,我会像这样为 (index) 路由定义一个模型

App.Index = DS.Model.extend({

        title: DS.attr('string'),

版本(很遗憾我不知道 Ember 数据的版本或我使用的适配器)

Ember Inspector
1.7.0
Ember
1.9.1
Ember Data
<%= versionStamp %>
Handlebars
2.0.0
jQuery
1.10.2

更新以响应更多信息的请求

设置问题的代码非常简单。 这是路由器(资源名称不好:) App.Router.map(function(){ this.resource('index', { path: '/'}); }

这是获取要在索引路由中使用的记录的路由

App.IndexRoute = Ember.Route.extend({
      model: function{
      var resource = this.store.find('index');
       return resource;
       }
     });

我有一个索引控制器,它对组件没有什么特别的作用(除非我应该在控制器上定义由组件事件触发的方法)

在 html 中,我使用把手来将数据传递给组件

   {{#each item in items}}
 <li> {{my-component id=item.customid data=item.stats notes=item.notes store=store}}                   
   {{/each}}

然后,在components/my-component 中,我有一个标签,单击该标签应该触发一个操作,让我编辑模型上的一个属性

<label> {{action "editTodo" on="doubleClick">{{notes}}</label>

点击触发App.MyComponent中的这段代码,触发提示这个问题的错误

 var todo = this.get('store')
 todo.set('notes', bufferedTitle);
 todo.save()

【问题讨论】:

标签: ember.js


【解决方案1】:

根据this doc向组件注入store的首选方式是给记录设置一个store变量,例如

{{#each item in arrangedContent}}
<li> {{my-component store=item}} </li>
{{/each}}

然后在应用程序代码中,你可以这样做

var store = this.get('store');
store.set('todo', bufferedTitle);

【讨论】:

    【解决方案2】:

    恕我直言,将store 注入组件并不是最好的主意...根据设计,组件应该是隔离的,并且不应该对store 有任何了解。

    在您提供的文档中,它是这样写的:通常,直接在组件中查找模型是一种反模式,您应该更愿意在包含组件。

    但是,如果您出于某种原因确实需要它,那么为什么不直接将变量 store 传递给组件呢?

    {{my-component store=store}}
    

    然后,您可以仅在您真正需要的组件中从控制器传递store

    在您的所有组件中注入store 很可能会导致您设计糟糕(尽管一开始看起来很诱人)。

    【讨论】:

      【解决方案3】:

      虽然接受的答案对于简单的应用程序是明智的,但如果该组件与 url 没有关系(例如侧栏内容或仪表板上的可配置小部件),则将商店注入组件是完全可以接受的。

      在这种情况下,您可以使用初始化程序将 store 注入到您的组件中。

      但是,在测试中模仿初始化器可能会很痛苦。我非常希望测试友好的优秀 Ember.inject API 将扩展到服务之外并适应商店。 (或者商店将简单地变成服务)。

      【讨论】:

      • 我开发了一个相当大的应用程序,但我们从未在任何组件中注入store。我猜如果你需要与路由器进行一些通信,组件应该触发一个动作,然后,这应该被可以访问store的控制器捕获。
      • 从组件中“触发动作”的问题在于它降低了使用组件的隔离性和干燥度。如果你使用一个在多个地方执行一个动作的组件,你必须定义一个相同的动作处理多个位置的父母。为什么不让组件决定效果呢?归根结底,除了查询参数之外,控制器实际上与组件没有什么不同,并且规定“只有这 2 件事(控制器/路由)可以做某事,但不能做其他 1 件事(组件)”违背了 零一无穷设计理念。
      【解决方案4】:

      这是 Ember 2 的更新答案:

      Ember Data 的 store 现在是 Service,我们可以通过 Initializer 轻松地将 inject 它添加到所有组件中,例如app/initializers/inject-store-into-components:

      export function initialize(application) {
        application.inject('component', 'store', 'service:store');
      }
      
      export default {
        name: 'inject-store-into-components',
        initialize,
      }
      

      然后,在您的组件中,您可以使用this.get('store') 访问商店。这避免了直接将 store 作为参数传递给组件的需要,这需要模板中的大量样板。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-12
        • 1970-01-01
        • 2013-08-09
        • 2019-03-24
        • 1970-01-01
        • 2014-10-28
        • 1970-01-01
        • 2017-10-21
        相关资源
        最近更新 更多