What is the “correct” approach when creating a new items which is to be added to a collection. I have an edit/create new template which based on url gets an existing Item or creates a new one.
How do I keep this new Item have its changes reflected in the DOM before actually updating the database.
For instance if Item(empty one) is:
{
name : “”,
books : []
}
So in the gui I want to return this empty item values(or an existin one). I also want to be able to populate the array. So if I input a book in the gui, in the event I push another “book” into the array and then I want the gui to re-render.
Usually in meteor(based on all examples) all changes are instant. Basically you have a helper that returns
Collection.find(); and then you just insert into the collection and the template rerender the new item.
Here I just want the presentation of the array to give me a new row when user pressed add new book. Then I manually will fetch data on save and insert(update) my item.
I am struggling with an example of best approach for this.
Reactive-object? In the helper create a reactive object from the item retrieved from the collection from the database:
Template.ItemEditor.helpers({
getItem : function() {
var item = Item.findOne(id);
// convert item to reactive object
});
Here I just want the presentation of the array to give me a new row when
user pressed add new book. Then I manually will fetch data on save and
insert(update) my item.
Is there any significant reason you’re not using method stubs for that?
in the onCreated I can just
this.model = new ReactiveVar(emptyObject);
it all works nicely.
However the collection does not seem to be ready. I still have unsecure package and autopublish packages on if that matters but I try: Model.findOne(id) and it returns undefined.
However if I run the exact same query in one event(so the page is fully loaded) I do get a result from Models.findOne (just to illiminate the possibility that it is the wrong id).
If I try
Items.findOne(myIdHere) later in the code it works so thats not the problem. It is as if it hasn’t synced yet for client to retrieve it or something?
I dont´t undestand very well what is your trying to say.
Can you create a github repo or … to see your code?
If you have autopublish and unsecure package Meteor.subscribe is not needed.
You put Models.findOne on a Tracker.autorun or Template helper?.
On client side findOne is a async function, not blocking , the first time is called it return “undefined” then it return the value, but for catch this value, findOne must be run on a reactive consumer.
Template helper are reactive consumers. You can do something like this:
onCreated and onRendered are not reactive consumers. You must put your code on a autorun. Something like:
Template.templateExampled.onCreated({
var value;
this.autorun(function(){
value = Model.findOne('wjQyQ6sGjzvNMDLiJ'); // hardcoded id. Only for simplify
});
});
All this code example are incomplete, lack many parts to be really useful … just for simplicity.
Template.emailGroupEdit.onCreated(function () {
this.model = new ReactiveVar({});
var id = FlowRouter.getParam("id");
isNew = !id;
var self = this;
// If we want a to edit a totally new item
if (isNew) {
this.model.set(emptyGroup);
}
else {
var result = Items.findOne(id);
//HERE! result is undefined.
// If I run Items.findOne(id) in an event(so later in the app state) same id gives a result which
// is not undefined (I mean I have tested that the id exists.)
this.model.set(result);
}
});
So at the moment of “onCreated” I cant use findOne on the collection because it gives undefined as a result.
I base my ideas from @corvid suggestion top which does not work.
@bysabi is correct. You are trying to get data from a reactive data source in a non-reactive way. Getting the result in a helper does the reactive wiring for you, otherwise you will need to wrap your code in a template autorun or in a Tracker.
if (isNew) {
this.model.set(emptyGroup);
}
else {
var result;
this.autorun(function() {
result = Items.findOne(id);
});
//HERE! result is undefined.
// If I run Items.findOne(id) in an event(so later in the app state) same id gives a result which
// is not undefined (I mean I have tested that the id exists.)
this.model.set(result);
}
As @bysabi demonstrated, Items.findOne({ _id: id }); needs to be placed inside a this.autorun block. The point is that this query will be re-run once the data arrives and matches your query. It’s not ridiculously hard as you say - you simply have yet to understand reactivity.
This worked. I guess I started blindly at corvins suggestion earlier which well does not work for me. Btw, the setting of the model property has to be inside the autorun, so when I move it into the autorun it works.
Thanks for your help.
Guess I will have to look into flow router and subscribing to publication when I remove autopublish and unsecure package.