Можно ли сделать модель маршрута вычисляемым / отслеживаемым свойством?
Я пытаюсь заставить крючок модели маршрута возвращать некоторый массив, который постоянно обновляется через механизм опроса с использованием Emberlater
. Файл маршрута выглядит так:
export default class IndexRoute extends Route {
recent: [],
init() {
...
this.getRecent();
}
getRecent() {
// poll data / fetch latest
this.recent.push(newStuff);
later(this, this.getRecent, 2000);
}
model() {
return this.recent;
}
}
Затем в своем контроллере я хотел создать @computed
/ @tracked
недвижимость на основе маршрута model
:
export default class IndexController extends Controller {
// @tracked model; // this also didn't work
@computed('model.@each') // this doesn't work
get computedModel() {
console.log('computedModel'); // prints only once, when the model hook is first run
return this.model;
}
}
Я думал, что то, что было предложено в этом сообщении, сработало бы, но этого не произошло:(
Я видел этот пост, но он был для Ember 1.13, так что это не совсем современное решение.
Точно так же и этот пост содержал устаревшее содержание.
Возможно ли то, что я пытаюсь сделать? В качестве альтернативы я думал о перемещении данных в контроллер и создании вместо этого вычисляемого свойства переменной контроллера. Принимаю все предложения!
1 ответ
Основная проблема вашего текущего подхода заключается в том, что вы не используете специальные функции Ember Array. Когда вы создаете массивы в Ember, часто случается некоторая магия, которая автоматически создает их как массивы Ember (по крайней мере, так было при использовании синтаксиса старого стиля с.create
и когда были разрешены расширения прототипов). Вы всегда можете явно создать массив Ember с помощью:
import { A } from '@ember/array';
export default class ApplicationRoute extends Route{
recent = A([]);
}
В любом случае, когда вы просто используете this.recent.push(newStuff);
, этот прототип встроенного массива не инструментирован таким образом, чтобы система отслеживания / наблюдателя Ember могла знать, что новое значение было добавлено к this.recent
и впоследствии вызвать повторную визуализацию. Это относится как к отслеживаемым свойствам, так и к традиционной системе наблюдения до Octane.
Вместо этого, при взаимодействии с массивами, которые отображаются в шаблонах (т.е. с массивами, которые необходимо отслеживать), вы должны использовать специальные Ember.Array
конкретные функции pushObject
нравиться this.recent.pushObject(newStuff)
.
getRecent() {
// poll data / fetch latest
this.recent.pushObject(this.current);
this.current = this.current + 1;
later(this, this.getRecent, 2000);
}
Если вы хотите полностью придерживаться отслеживаемого стиля свойства, вы можете избежать использования массива Ember, но вы должны принудительно выполнить повторное вычисление, переназначив массив отслеживаемому свойству. Вот пример компонента
import Component from '@glimmer/component';
import { tracked} from '@glimmer/tracking';
import { later } from '@ember/runloop';
export default class extends Component {
@tracked
trackedArray = [];
current = 0;
constructor(){
super(...arguments);
this.doPoll();
}
doPoll() {
// essentially pushing but via a reassign with the new element
// you could also `pushObject` here if that feels better
this.trackedArray = [...this.trackedArray, this.current];
this.current = this.current + 1;
later(this, this.doPoll, 2000);
}
}
Вот Ember Twiddle, демонстрирующий оба подхода в действии.
PS. Вmodel
свойство маршрута только квазидинамическое. Во время перехода возвращаемое значениеmodel
крючок автоматически назначается маршруту currentModel
свойство. Это значение затем передается вsetupController
как второй параметр и автоматически назначается контроллеру model
собственность, если нет setupController
определено, или если setupController
призывает super
базовой реализации. когдаmodelFor
вызывается для определенного маршрута, currentModel
имущество возвращается и model
не вызывается повторно. Это все, чтобы сказать, что голосование вmodel
сама функция не будет автоматически обновлять model
свойство. В вашем примере все работает нормально, так какmodel
ссылка никогда не меняется (вы просто изменяете массив).