How can I get Iron Router to wait for a db insert before continuing?


#1

I have a feature in which locally saved content for anonymous users is saved to the db after a user signs in. After the local content has been inserted to the db, I want to redirect to the new post.

The challenge I am facing is how to get Iron Router to wait for the insert to complete before redirecting to the new post. The current version below works, but it feels clunky and I get the following warning from Iron Router because I am using Router.go rather than this.next(): Route dispatch never rendered. Did you forget to call this.next() in an onBeforeAction?

What is a better way (than below) to wait for a db insert to complete before redirecting to the new item/post?

Triggering Event

User initiates login via 3rd party. (I am using vanilla Accounts-UI/LoginButtons)

First Before Hook: Check if there is local content
I have a session var that is set to true if locally stored content has been entered.

Router.onBeforeAction(function checkIfLocalContentOnLogin(){

  if(Meteor.loggingIn() && Session.get("hasLocalContent")){
    Session.set("startSaveToAcct", true);
  } 
  this.next(); 
}
);

Second Before Hook: Runs after user is signed in and local content was found

Router.onBeforeAction(function saveToAcct(){
  
  if(Meteor.userId() && Session.get("startSaveToAcct")){
        var postAttributes = {
          title: Session.get("docTitle"),
          content: Session.get("localContent")
        };
    
       //I would like to wait for this to be ready before continuing.
        Meteor.call('createPost', postAttributes, function(error, result){
          if (error){
             console.log("create post error: " + error.reason);
          } else {
            Session.setPersistent("localContent", "");
            Session.set("docTitle", "");
            Session.set("startSaveToAcct", false);
    
           // I cannot call "this.redirect(...)" from in here, which is why I get the IR warning
            Router.go('editPost', { _id: result._id });
          }
        });

       //I would like to be able to call "this.redirect(...)" from here, but cannot do so because I can't get IR to wait for the above Meteor.call method (on the client, which is async) before continuing.
    
      } else {
         this.next();
      };

});

Any suggestions re. a better way of doing this (eg without the IR warning, and maybe a bit less clunky) would be appreciated!


#2

Cant you just create some ReactiveVar which will represent if it is loaded.
And than in action: call render only if it has correct value ?

Still I dont understand why you are in Router hooks. I would be handling whole sign procedure on the old URL and just call redirect/go when the document is really inserted.


#3
MyCollection.insert({ }, function (err) {
  if (!err) {
    Router.go('/your-route');
  }
});

#4

@shock I tried using a Session variable, but I could not get IR to wait for the Session variable to return true. The only thing, it seems, that one can get IR to wait for is a subscription.

Re. your suggestion to handle this in the old URL, I’m not sure what URL that would be, since the triggering event for all this is that the user signs in via a 3rd party.


#5

@corvid - this is basically what I currently am doing. However, using Router.go (or more specifically, not using this.redirect or this.next) leads to a “Route dispatch never rendered…” warning from IR, and I cannot call those from within a MyCollection.insert()


#6

since Method.calls are asynchronous, this makes sense. Why don’t you redirect the user to an intermediary page at the location where you have the comment?

//I would like to be able to call "this.redirect(...)" from here, but cannot do so because I can't get IR to wait for the above Meteor.call method (on the client, which is async) before continuing.