Create a new object


#1

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 .


#2

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

#3

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?


#4

Care to elaborate on which part you mean?


#5

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?


#6

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


#7

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?


#8

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.


#9

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.


#10

Why not just render autoform insert form ?


#11

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 …


#12

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


#13

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

#14

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.


#15

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.


#16

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.