2017-01-19 4 views
4

Мое приложение использует службу websocket на основе ember-phoenix, чтобы выталкивать новые записи из API в магазин. Я бы хотел, чтобы эти новые записи отображались в моем шаблоне, когда они были добавлены.Добавление новых данных через websocket при использовании store.query в пути

У меня есть маршрут, где модель крюк возвращает фильтрованную обещание запроса:

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); 
    }, 
}); 

ответ

3

Вариант 1
Вы можете использовать Ember.Evented подписаться и события отправки. Я создал twiddle для демонстрации.

socket В службе,

  • socket должен расширить класс Ember.Evented

    export default PhoenixSocket.extend(Ember.Evented, {

  • После обновления магазина, вы можете просто вызвать myModelDataLoaded, который будет направлять все функции подписался myModelDataLoaded.

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

В пути,

  • Вы можете подписаться на myModelDataLoaded
 
afterModel() { 
     get(this, 'socket').joinSchedule(); 
     get(this, 'socket').on('myModelDataLoaded', this, this.refreshRoute); //we are subscribing to myModelDataLoaded 
    } 
  • Определить функцию refreshRoute и вызвать refresh функцию.

     
        refreshRoute() { 
         this.refresh(); //forcing this route to refresh 
        } 
    
  • Чтобы избежать необходимости утечки памяти в off ПОДПИСКА, вы можете сделать это либо в resetController или deactivate крючок.
     
    resetController() { 
        get(this, 'socket').leaveSchedule(); 
        get(this, 'socket').off('myModelDataLoaded', this, this.refreshRoute); 
    } 
    

Вариант 2.
Вы можете посмотреть магазин, используя peekAll с наблюдателем и обновить маршрут.

В вашем контроллере
1. Определите postModel вычисленное свойство, которое вернет массив живой записи.
2. Определите postModelObserver в зависимости от postModel.[] это обеспечит, когда в магазине будет обновлена ​​новая строка, это будет соблюдено myModelObserver, и оно отправит действие refreshRoute на маршрут. где мы будем называть refresh. Как вы знаете, это вызовет beforeModel, model, afterModel метод.

Как вы знаете, вычисленное свойство является ленивым, когда вы обращаетесь к нему только тогда, оно будет вычислено. так что если вы не используете его в шаблоне, то просто добавьте this.get('myModel') в init методе

файл контроллер

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'); 
    }) 
}); 

Route файл - определить действие 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(); 
     }, 
    } 
}); 
+1

Спасибо за подробный ответ! Я закончил делать то, что вы предложили в варианте 1, на основе ответа, который @xoma опубликовал выше, но я дам вам кредит, так как вы потратили время на его документирование для людей в будущем. –

1

Вы можете вызвать событие из вашей службы WebSocket, когда вы получите сообщение на сокет, а затем подписаться на него в вашем маршруте, а затем вызвать обновление(), чтобы перезагрузить вашу модель. Существует также https://github.com/ember-data/ember-data-filter - который перенастраивает живой массив.

0

Это не лучший способ, но один из способов сделать ваш существующий код - использовать обратный вызов.

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() { 
    let cb = (myModelRecord) => { 
     this.get('model').push(myModelRecord); 
    }; 
    get(this, 'socket').joinSchedule(cb); 
    }, 

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

}); 

вызова метода обратного вызова службы сокета,

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(cb) { 
    const channel = this.joinChannel(`v1:my-model`); 

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

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