我的应用程序使用基于 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 inresetController
ordeactivate
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/