Autoform troubles

I’m new to Meteor and working on a “learning” project. I’m adapting a tutorial app for my own purposes (thank you George McKnight for the meteorshop video and repo!).

I’ve added peppelg:bootstrap-3-modal and aldeed:autoform to my project and I’ve setup this template:

<template name="productModalEdit">
  <div class="modal fade" role="dialog">
    <div class="modal-dialog" >
      <div class="modal-content">
        <div class="modal-header">
          <h4 class="modal-title">Edit Product</h4>
        </div>
        <div class="modal-body">
            {{#autoForm id="afUpdateProduct" doc=selectedProductDoc type="method-update" singleMethodArgument=false meteormethod="editProduct" collection=Collections.Products}}
              <fieldset>
                  {{> afQuickField name='name'}}
                  {{> afQuickField name='desc' rows=4}}
                  {{> afQuickField name='price'}}
                  {{> afQuickField name='thumb'}}
                  {{> afQuickField name='catName'}}
              </fieldset>
              <div class="form-group">
                <button type="submit" class="btn btn-primary" id="save">Save Product</button>
                <button type="reset" class="btn btn-default">Reset Form</button>
              </div>
            {{/autoForm}}
        </div>
      </div>
    </div>
  </div>
</template>

There’s actually an almost duplicate template for inserting, so I call different templates for insert vs. update. There are two different meteor methods that correspond with each operation.

I have the following client javascript:

// helper to get the product categories out of the database
Template.productModalNew.helpers({
  categories:function(){
    return SubCategories.find().map(function (doc) {
      return doc.name;
    })
  }
});

// add or update events for the product modal form template
Template.productModalNew.events({
  'click #save': function(e) {
    e.preventDefault();
    Modal.hide('productModalNew');
  }
});

Template.productModalEdit.helpers({
  categories:function(){
    return SubCategories.find().map(function (doc) {
      return doc.name;
    })
  },

  selectedProductDoc: function () {
    return Products.findOne(Session.get("selectedProductId"));
  }
});

// add or update events for the product modal form template
Template.productModalEdit.events({
  'click #save': function(e) {
    e.preventDefault();
    Modal.hide('productModalNew');
  }
});

Schemas = {};

Schemas.Product = new SimpleSchema({
  name: {
    type: String,
    index: 1,
    unique: true
  },
  desc: {
    type: String,
    optional: true
  },
  price: {
    type: Number,
    decimal: true,
    optional: true
  },
  catName: {
    type: String,
    optional: true
  },
  thumb: {
    type: String,
    optional: true
  }
});

var Collections = {};
Products = Collections.Products = new Mongo.Collection("Products");
Products.attachSchema(Schemas.Product);

// make sure the templates know about these helpers
Template.registerHelper("Schemas", Schemas);
Template.registerHelper("Collections", Collections);

// data access rules 
// TODO: add some real rules to these
Products.allow({
  insert: function () {
    return true;
  },
  update: function () {
    return true;
  },
  remove: function () {
    return true;
  }
});

Meteor.subscribe('products');

And this is the server code:

Meteor.methods({
  addProduct:function(product){
      var prod_id = Products.insert(product);
      return prod_id;
  },

  editProduct:function(product, doc_id) {
    Products.update({_id:doc_id},product);
  }

});

This all seems to be right out of the documentation, and almost everything works, except for the actual method calls. I’m not reaching the methods when I do a form submit. The weird thing is I had this working and somehow I’ve broken it.

Since I had it working I did remove the autopublish package, but I’m pretty sure I have the publish/subscribe thing all sorted out properly.

Is there anything obvious here that I have wrong? I’ve tried to use AnyForm.debug() to no avail. Obviously I don’t know how to do that correctly, and the documentation for it is “thin”, from what I’ve found so far.

Also, when I try to use collection="Products" rather than collection=Collections.Products things stop working (the form doesn’t render any fields). That would seem to be a clue that my Collections aren’t being recognized properly, but I have no idea why that would be.

Any pointers would be greatly appreciated. I’ve been over the AutoForm documentation about a dozen times and I’m getting nowhere fast with that path. If I’ve left out any important parts of the code please let me know and I’ll gladly get it in here.

  1. You attach schema only to Products, not to Collections.Products.

  2. Remember to use check in methods, Autoform by default uses check only for type=“insert” and type=“update”, in methods you need to do this yourself.

  3. What do you need that for? -> // make sure the templates know about these helpers

  4. With autoform, use type=“button” instead of type=“submit”. You won’t have to do e.preventDefault();

Perhaps it’s even this e.preventDefault(); that doesn’t allow Autoform to call the method.

OK, so are you saying that I need to do this:

Products.attachSchema(Schemas.Product);
Collections.Products.attachSchema(Schemas.Product);

I did that and the autoform still didn’t like the collection="Products" syntax. The form renders with no fields (only the buttons display) if I use that for the collection argument. I changed it back to collection=Collections.Products and that seems to be what it likes. I’d really like to know what it takes to make the collection="Product" syntax work. It’s more standard HTML to have the attribute arguments in quotes.

I’ll do that, after I actually get the form working. I didn’t want to complicate things if the basic form functions didn’t work. Thanks for the reminder though.

Those Template.registerHelper snippets came directly from the AutoForm documentation. I assumed they were required to register the simple-schema and collection2 objects with the template. If not, that’s great. Just trying to follow the documentation. Should I remove them?

I actually read a post on the forum (or the github issues log) that said that the button needed to be type="submit" or it wouldn’t trigger the method correctly. FYI, I left my buttons as type="submit" after I commented out the e.preventDefault(); and the form started working, so I think that was the problem.

I had the e.preventDefault(); in the method from the previous version of my project, which didn’t use Autoform, so that was obviously a problem I introduced and an important lesson learned. That seemed to do the trick.

Your comments were great and very helpful. They helped me sort this out and get a better perspective on what it takes to make Autoform work. Thanks very much.

1 Like

I’m glad it’s working now. :smile:

I’m saying that if you specify collection=’’ in autoform, it needs to be a collection with attached schema. So if you do collection=‘Collection.Products’, Collection.Products needs the schema attached. Personally I don’t namespace collections, but it’s a matter of preference.

I’m always using this syntax and it works for me out of the box.

But there is a valid reason for the lack of quotes. With quotes, you pass a string with the name of the collection (or the name of the object - I’m not sure because I always name them the same). But without the quotes, you pass the value of the helper. Which is related to the next case:

Ah, it seems I missed it in the documentation. I use collection=“string” which accepts a string, so I do not need to register any helper. You register a helper in order to use collection=helper instead. Both options work, again a matter of preference.

It was probably a fixed issue, because it totally does work for me. Or maybe the issue is related only to type=“insert” and “update”, not server side methods. I always use server side and as I see, you do too.

This code works for me:

Products = new Mongo.Collection("Products");
Schemas.Products = new SimpleSchema({ 
  name: {
    type: String,
    index: 1,
    unique: true
  }
});
Products.attachSchema(Schemas.Products);

{{#autoForm collection="Products" (...) }}