Реактивность метеорного метода не работает
У меня нет опыта работы с Javascript, но я прочитал тонну статей о реактивности Метеора, но до сих пор не могу понять, почему она не работает в моем случае.
Когда добавляется новый продукт, я хочу пересчитать общую стоимость и использовать его в помощнике totalCost, чтобы он почти в реальном времени отображался в браузере.
Может кто-нибудь взглянуть на мой код и попытаться выяснить логическую ошибку? Все, кроме реактивности, работает на моем компьютере.
У меня есть этот метод в /models/Product.js
:
Meteor.methods({
totalProductCost: function() {
var pipeline = [
{$match: {owner: Meteor.userId()}},
{$group: {_id: null, cost: {$sum: "$cost"}}}
];
var data = Products.aggregate(pipeline)["0"].cost;
return (data === undefined) ? 0 : data;
}
});
Тогда у меня есть layout.js в папке клиента:
if (Meteor.isClient) {
var handle = Meteor.subscribe("Products", Meteor.userId());
ProductManager = {
_productItems: null,
_dep: new Tracker.Dependency(),
getProducts: function () {
this._dep.depend();
return this._productItems;
},
setProducts: function (value) {
if (value !== this._productItems) {
this._productItems = value;
this._dep.changed();
}
},
getTotalCost: function () {
return ReactiveMethod.call('totalProductCost');
}
}
// TRACKER
Tracker.autorun(function () {
if (handle.ready()) {
ProductManager.setProducts(Products.find().fetch());
}
});
// HELPERS
Template.boxOverview.helpers({
"totalCost" : function () {
return ProductManager.getTotalCost();
},
});
}
1 ответ
Кажется, вы использовали collection.aggregate
в методе. Если вам нужна реактивность, вам нужно использовать публикацию, а не метод (или вам нужно вызывать метод каждый раз, когда вы хотите обновить). Однако, если вы используете агрегацию внутри своей публикации (я предполагаю, что вы используете пакет для нее), вы также потеряете реактивность.
Я бы посоветовал вам использовать публикацию без aggregate
функция. Вы рассчитываете стоимость продукта, создавая новое поле и добавляя его к своему курсору. После того, как вы сделаете это, если вы хотите сохранить реактивность, необходимо использовать для использования cursor.observeChanges()
или просто cursor.observe()
,
Посмотрите на этот пример:
var self = this;
// Modify the document we are sending to the client.
function filter(doc) {
var length = doc.item.length;
// White list the fields you want to publish.
var docToPublish = _.pick(doc, [
'someOtherField'
]);
// Add your custom fields.
docToPublish.itemLength = length;
return docToPublish;
}
var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
// Use observe since it gives us the the old and new document when something is changing.
// If this becomes a performance issue then consider using observeChanges,
// but its usually a lot simpler to use observe in cases like this.
.observe({
added: function(doc) {
self.added("myCollection", doc._id, filter(doc));
},
changed: function(newDocument, oldDocument)
// When the item count is changing, send update to client.
if (newDocument.item.length !== oldDocument.item.length)
self.changed("myCollection", newDocument._id, filter(newDocument));
},
removed: function(doc) {
self.removed("myCollection", doc._id);
});
self.ready();
self.onStop(function () {
handle.stop();
});
Это взято отсюда.