我的应用程序使用基于 ember-phoenix 的 websocket 服务将新记录从 API 推送到商店。我希望这些新记录在添加时呈现在我的模板中。

我有一个路径,模型钩子(Hook)返回一个过滤的查询 promise :

import Ember from 'ember';

const {
  get,
  inject,
} = Ember;

export default Ember.Route.extend({
  socket: inject.service(),

  model(params) {
    return this.store.query('my-model', {filter: {date: params.date}})
  },

  afterModel() {
    get(this, 'socket').joinSchedule();
  },

  resetController() {
    get(this, 'socket').leaveSchedule();
  },

});

当新记录通过 websocket 推送到商店时,由于 store.query 的工作方式,它们不会由我的模板呈现。如果我将 store.query 更改为 store.findAll,则会呈现新记录,但我希望我的路由仅根据日期查询参数加载所有记录的子集。

似乎我唯一的选择是在将新记录推送到商店时重新加载路线的模型。是否可以从服务中做到这一点?如果没有,我可能想探索一种不同的方法吗?

我的套接字服务的相关部分如下:
import Ember from 'ember';
import PhoenixSocket from 'phoenix/services/phoenix-socket';

const {
  get,
  inject,
} = Ember;

export default PhoenixSocket.extend({
  session: inject.service(),
  store:   inject.service(),

  joinSchedule() {
    const channel = this.joinChannel(`v1:my-model`);

    channel.on('sync', (payload) => this._handleSync(payload));
  },

  _handleSync(payload) {
    get(this, 'store').pushPayload(payload);
  },
});

最佳答案

选项 1
您可以使用 Ember.Evented 订阅和调度事件。我创建了 twiddle 用于演示。

socket 服务中,

  • socket 应该扩展 Ember.Evented
    export default PhoenixSocket.extend(Ember.Evented, {
  • After updating store, you can just trigger myModelDataLoaded which will dispatch all the functions subscribed to myModelDataLoaded.

     _handleSync(payload) {
            get(this, 'store').pushPayload(payload);
            this.trigger('myModelDataLoaded'); //this will call the functions subscribed to myModelDataLoaded.
        }
  • In Route,

    • You can subscribe to myModelDataLoaded
    afterModel() {
            get(this, 'socket').joinSchedule();
            get(this, 'socket').on('myModelDataLoaded', this, this.refreshRoute); //we are subscribing to myModelDataLoaded
        }
    
    • Define refreshRoute function and call refresh function.

         refreshRoute() {
              this.refresh(); //forcing this route to refresh
          }
      
    • To avoid memory leak need to off subscribtion, you can do it either in resetController or deactivate hook.
      resetController() {
          get(this, 'socket').leaveSchedule();
          get(this, 'socket').off('myModelDataLoaded', this, this.refreshRoute);
      }
      

    Option 2.
    You can watch store using peekAll with observer and refresh route.

    In your controller,
    1. Define postModel computed property which will return live record array.
    2. Define postModelObserver dependant on postModel.[] this will ensure whenever store is updated with new row, it will be observed by myModelObserver and it will send action refreshRoute to route . where we will call refresh. As you know this will call beforeModel, model, afterModel method.

    As you know computed property is lazy, when you are accessing it only then it will be computed. so if you are not using it in template, then just add this.get('myModel') in init method

    Controller file

    import Ember from 'ember';
    const { computed } = Ember;
    export default Ember.Controller.extend({
        init() {
            this._super(...arguments);
            this.get('postModel');//this is just to trigger myModel computed property
        },
        postModel: computed(function() {
            return this.get('store').peekAll('post');
        }),
        postModelObserver: Ember.observer('postModel.[]', function() {
            this.send('refreshRoute');
        })
    });
    

    路由文件 - 定义用于刷新的 Action refreshRoute,因为 refresh 仅在路由中可用。
    import Ember from 'ember';
    
    const {
        get,
        inject,
    } = Ember;
    
    export default Ember.Route.extend({
        socket: inject.service(),
        model(params) {
            return this.store.query('my-model', { filter: { date: params.date } })
        },
    
        afterModel() {
            get(this, 'socket').joinSchedule();
        },
    
        resetController() {
            get(this, 'socket').leaveSchedule();
        },
        actions:{
            refreshRoute() {
                this.refresh();
            },
        }
    });
    

    关于ember.js - 在路由中使用 store.query 时通过 websocket 添加新数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41752676/

    10-13 03:36