Create a new object

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

Sorry for long post, just hard to explain .

You can make a new reactive object like this (assuming you’re using Flow Router)

Template.myTemplate.onCreated(function () {
  this.model = new ReactiveVar({});
  if (FlowRouter.subsReady('your-sub')) {
    this.model.set(Models.findOne(id));
  }
});

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?

Care to elaborate on which part you mean?

For a new object:

var emptyObject = {
    name : "",
    books : []
   }

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).

I tried adding in my route:

subscriptions: function(params, queryParams) {
        this.register('items', Meteor.subscribe('items¨'));
    }

Ideas?

You can test 3T MongoChef to see what is on your MongoDB.
This tool have a free version mode.

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:

Template.templateExample.helpers({
  model: function(id) {
   return Models.findOne(id);
 }
}

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.

1 Like

lib/collection/item

`Items = new Mongo.Collection('items');

Template.js:

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.

Why not just render autoform insert form ?

I could use autoform but well I want to know how it works and this seems like a so trivial task that it is ridicioulus how hard it seem to be!

Read item from database, display in gui, edit, save …

@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.

must be:

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.

I suggest read this and try to undestand it, is the key to advance on meteor client side:

http://stephenwalther.com/archive/2014/12/05/dont-do-react-understanding-meteor-reactive-programming

https://www.discovermeteor.com/blog/reactivity-basics-meteors-magic-demystified/

put your time on this.

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.