简体   繁体   中英

Two-way data binding for a Meteor app

I've built an app that is form-based. I want to enable users to partially fill out a form, and then come back to it at a later date if they can't finish it at the present. I've used iron router to create a unique URL for each form instance, so they can come back to the link. My problem is that Meteor doesn't automatically save the values in the inputs, and the form comes up blank when it is revisited/refreshes. I tried the below solution to store the data in a temporary document in a separate Mongo collection called "NewScreen", and then reference that document every time the template is (re)rendered to auto fill the form. However, I keep getting an error that the element I'm trying to reference is "undefined". The weird thing is that sometimes it works, sometimes it doesn't. I've tried setting a recursive setTimeout function, but on the times it fails, that doesn't work either. Any insight would be greatly appreciated. Or, if I'm going about this all wrong, feel free to suggest a different approach:

Screens = new Meteor.Collection('screens') //where data will ultimately be stored
Forms = new Meteor.Collection('forms') //Meteor pulls form questions from here
NewScreen = new Meteor.Collection('newscreen') //temporary storage collection
Roles = new Meteor.Collection('roles'); //displays list of metadata about screens in a dashboard

//dynamic routing for unique instance of blank form
Router.route('/forms/:_id', {
  name: 'BlankForm',
  data: function(){ 
    return NewScreen.findOne({_id: this.params._id});
  }
});

//onRendered function to pull data from NewScreen collection (this is where I get the error)
Template.BlankForm.onRendered(function(){
  var new_screen = NewScreen.findOne({_id: window.location.href.split('/')[window.location.href.split('/').length-1]})
  function do_work(){
    if(typeof new_screen === 'undefined'){
      console.log('waiting...');
      Meteor.setTimeout(do_work, 100);
    }else{
      $('input')[0].value = new_screen.first;
      for(i=0;i<new_screen.answers.length;i++){
        $('textarea')[i].value = new_screen.answers[i];
      }
    }
  }
  do_work(); 
}); 

//onChange event that updates the NewScreen document when user updates value of input in the form
'change [id="on-change"]': function(e, tmpl){
      var screen_data = [];
      var name = $('input')[0].value;
      for(i=0; i<$('textarea').length;i++){
        screen_data.push($('textarea')[i].value);
      }

      Session.set("updateNewScreen", this._id);

        NewScreen.update(
          Session.get("updateNewScreen"),
          {$set: 
            {
              answers: screen_data,
              first: name
            }
          });
      console.log(screen_data);
    }

If you get undefined that could mean findOne() did not find the newscreen with the Id that was passed in from the url. To investigate this, add an extra line like console.log(window.location.href.split('/')[window.location.href.split('/').length-1], JSON.stringify(new_screen)); This will give you both the Id from the url and the new_screen that was found.

I would recommend using Router.current().location.get().path instead of window.location.href since you use IR.

And if you're looking for two way binding in the client, have a look at Viewmodel for Meteor .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM