[SOLVED] Auto-create a post on "New" to support auto-saving of changes


#1

TL:DR
I am not able to get Iron Router to wait for a record to be created and then pass the id of that record to the current route. I have tried finding answers to this in the Iron Router Guide and elsewhere, but nothing seems to work.


  • I am working on a note-taking app, mostly for learning purposes.
  • I would like to implement my note form such that changes are auto-saved as I type (for example, something like this)

My Goal: the experience I would like to support

  1. User clicks on “New Note”
  2. A blank note form is displayed
  3. As the user types, changes are auto-saved.

What I’m assuming
For this to be possible, I am assuming that, on click of “New Note” that I will need to actually create a note for it to be possible to auto-save changes as they type. Is this a correct assumption? I don’t see any other way to be able to auto-save without having a note id in the params.

The issue
On create of a new note in my controller, I am not able to get the controller to wait for note creation to complete and instead get the following error:

Error: Missing required parameters on path "/notes/:_id/edit". The missing params are: ["_id"]. The params object passed in was: undefined.

My current Code for creating a note on “New Note” Action

(1) On click on “New Note” button:

Session.set("newNote", true); Router.go('edit_note'); // Is the issue that Iron Router is expecting an id value already here, which is why everything else appears to be ignored? If so, can I use a different method to call the controller which doesn't expect the param value?

(2) In the EditPostController, I have a before action that creates a new note if the session variable returns true. However, it appears that the before action either doesn’t run at all or doesn’t complete.

EditPostController = RouteController.extend({
  template:'edit_post',
  onBeforeAction: function (){
    
    if (Session.get("newPost")){
      var postAttributes = {
        title: "New Post"
      };
   
    //My goal here is to get the newly created id and pass it into params - this is likely incorrect - any suggestions on how to fix this?    
    this.params._id = Meteor.call('createPost', postAttributes, function(error, result){
      if (error){
        alert(error.reason);
      } else {
         return result._id;
      };
    });
  };

      this.next();
  },
  waitOn: function () {
      // It does not appear as if this actually waits for the before action to complete
      return Meteor.subscribe('posts', this.params._id).wait();
  },
  data: function() {
       return Posts.findOne({ _id: this.params._id });      
  },
  action: function(){
   // this also does not appear to have any impact
    if (this.ready()) {
      this.render();
    } else {
      this.render('Loading');
    };
  }
});

#2

Why not just call that Router.go in callback of method used to create that note. Or insert callback, if you are using direct collection inserts ? In both cases you will have _id in result.


#3

@shock - yes, I was just looking at the code and realizing that the issue might be in the Router.go call. Thanks for the suggestion!


#4

Yes, that was the issue. It’s obvious now that that is what I should have done.

 "click .new-note": function(event) {
    event.preventDefault();
    
    var noteAttributes = {
      title: "New Note"
    };

    Meteor.call('createNote', noteAttributes, function(error, result){
      if (error){
        alert(error.reason);
      } else {
        Router.go('edit_note', {_id: result._id});
      };
    });
 }

and…

EditNoteController = RouteController.extend({
  template:'edit_note',
  waitOn: function () {
    return Meteor.subscribe('notes', this.params._id);   
  },
  data: function() {
    return Notes.findOne({ _id: this.params._id });   
  },
  action: function(){
    if (this.ready()) {
      this.render();
    } else {
      this.render('Loading');
    };
  }
});