AutoForm/Simple Schema Issue

I am having some difficulty getting an autoform to save. This is a new issue for me; so I am a little unsure on how to fix it.

I have the following form:

<template name="TaskItems">
  {{#if inspectionMode}}
    <a href="#" class="inspection btn btn-danger">Close Task <i class="glyphicon glyphicon-minus"></i></a>
    <table class="table table-striped">
      <thead>
        <tr>
          <th>Facility Section</th>
          <th>Title</th>
          <th>Section</th>
          <th>Code</th>
          <th>Pass/Fail</th>
        </tr>
      </thead>
      <tbody>
        {{#each TaskItem}}
            <tr>
              <td>{{DataFacilitySection}}</td>
              <td>{{DataItemDescription}}</td>
              <td>{{DataItemSection}}</td>
              <td>{{DataItemCode}}</td>
              <td>
                {{#autoForm id=itemUpdateForm collection="ClientData" type="update" autosave=true template="custom" doc=this}}
                  {{> afFormGroup name="DataItemPass" label=false}}
                {{/autoForm}}
              </td>
            </tr>
        {{/each}}
      </tbody>
    </table>
    {{else}}
    <a href="#" class="inspection btn btn-success">Begin Task <i class="glyphicon glyphicon-pencil"></i></a>
  {{/if}}
</template

The id logic is here:

  itemUpdateForm: function() {
    return Template.parentData(2)._id;
  },

I did add SimpleSchema.debug = true; and it gives the following error:

SimpleSchema.clean: filtered out value that would have affected key “DataItemPass”, which is not allowed by the schema

The field is pulling in the correct data (the field is filled out) but when I click off the field it does not save. I tried adding a submit button to see if that may change things, but it had no effect.

I can add the schema to the post if that is helpful. Any suggestions would be most appreciated!

Yes, please show us the schema :slight_smile:

1 Like

Sure! Here is the complete Schema! :slight_smile: The actual array is the “TasksWithData” portion near the bottom. Sorry I know its long!

ClientData = new Mongo.Collection('clients');

var createThumb = function(fileObj, readStream, writeStream) {
  // Transform the image into a 10x10px thumbnail
  gm(readStream, fileObj.name()).resize('40', '40').stream().pipe(writeStream);
};

var createBigThumb = function(fileObj, readStream, writeStream) {
  // Transform the image into a 10x10px thumbnail
  gm(readStream, fileObj.name()).resize('150', '150').stream().pipe(writeStream);
};

Images = new FS.Collection("images", {
	stores: [
    new FS.Store.FileSystem("thumbs", { transformWrite: createThumb }),
    new FS.Store.FileSystem("bigthumbs", { transformWrite: createBigThumb }),
    new FS.Store.FileSystem("images"),
  ],
  filter: {
    allow: {
      contentTypes: ['image/*'] //allow only images in this FS.Collection
    }
  }
});

Images.allow({
  insert: function(userId, doc) {
    return true;
  },
  update: function(userId, doc, fieldNames, modifier) {
    return true;
  },
  download: function(userId) {
    return true;
  }
});

//begin client data
ClientData.allow({
	insert: function(userId, doc) {
		return true;
	},
	update: function (userId, doc) {
		return true;
	}
});

TaskImages = new SimpleSchema({
  taskImages: {
    type: [String],
    label: "Add Images",
    optional: true,
  },
  "taskImages.$": {
    autoform: {
      afFieldInput: {
        type: "fileUpload",
        collection: "Images"
      }
    }
  },
});


ClientFacilities = new SimpleSchema({
  facilityName: {
    type: String,
    label: "Choose Facility",
    optional: true,
    autoform: {
      firstOption: 'Choose a Facility',
      options: function() {
        return FacilityData.find({}, {
          sort: {
            name: 1,
            id: 1
          }
        }).map( function ( c ){
          return{
            label: c.name,
            value: c.name + " - " + "ID: " + c.id,
          };
        } );
      }
    }
  },
  facilityAddress: {
    type: String,
    label: "Confirm Facility",
    optional: true,
    autoform: {
      firstOption: 'Confirm Facility',
      options: function() {
        return FacilityData.find({}, {
          sort: {
            name: 1,
            address: 1,
            special: 1
          }
        }).map( function ( c ){
          return{
            label: c.name + " - " + c.address,
            value: c.address
          };
        } );
      }
    }
  }
});

ClientContact = new SimpleSchema({
	fullname: {
		type: String,
		label: "Full Name"
	},
	email: {
		type: String,
		label: "Email Address",
		autoform: {
			afFieldInput: {
				type: "email"
			}
		}
	},
	phone: {
		type: Number,
		label: "Primary Phone",
		autoform: {
			afFieldInput: {
				type: "tel"
			}
		}
	},
	phone2: {
		type: Number,
		label: "Secondary Phone",
		optional: true,
		autoform: {
			afFieldInput: {
				type: "tel"
			}
		}
	}
});

ClientDataSchema = new SimpleSchema({
	clientName: {
		type: String,
		label: "Client Name",
		optional: true
	},
	clientInfo: {
		type: [ClientContact],
		label: "Client Contacts",
		optional: true,
		autoform: {
			initialCount: 0
		}
	},
	facilityList: {
		type: [ClientFacilities],
		label: "Client Facilities",
		optional: true,
		autoform: {
			initialCount: 0
		}
	},

  //TODO: Eventually move this to its own Schema File
  //All schema for adding tasks that contain data from the templates.
  TasksWithData: {
	  type: Array,
    optional: true
  },

  'TasksWithData.$': {
	  type: Object,
    optional: true
  },

  'TasksWithData.$.inspectionDetails': {
	  type: Array,
    optional: true
  },

  'TasksWithData.$.inspectionDetails': {
    type: Array,
    optional: true
  },

  'TasksWithData.$.inspectionDetails.$': {
    type: Object,
    optional: true
  },

  'TasksWithData.$.inspectionDetails.$.TaskFacility': {
    type: String,
    label: "Choose a Facility",
    optional: true,
    autoform: {
      firstOption: 'Choose an Facility',
      options: function() {
        return FacilityData.find({}, {
          sort: {
            name: 1,
            address: 1
          }
        }).map( function ( c ){
          return{
            label: c.name + " " + c.address,
            value: c.name + " " + c.address
          };
        } );
      }
    }
  },

  'TasksWithData.$.inspectionDetails.$.inspector': {
    type: String,
    label: "Inspector",
    optional: true,
    autoform: {
      firstOption: 'Choose an Inspector',
      options: function() {
        return Meteor.users.find({}, {
          sort: {
            profile: 1,
            firstName: 1
          }
        }).map( function ( c ){
          return{
            label: c.profile.firstName + " " + c.profile.lastName,
            value: c._id
          };
        } );
      }
    }
  },

  'TasksWithData.$.inspectionDetails.$.inspectorName': {
    type: String,
    label: "Confirm Inspector",
    optional: true,
    autoform: {
      firstOption: 'Choose an Inspector',
      options: function() {
        return Meteor.users.find({}, {
          sort: {
            profile: 1,
            firstName: 1
          }
        }).map( function ( c ){
          return{
            label: c.profile.firstName + " " + c.profile.lastName,
            value: c.profile.firstName + " " + c.profile.lastName
          };
        });
      }
    }
  },

  'TasksWithData.$.inspectionDetails.$.projectType': {
    type: String,
    label: "Project Type",
    optional: true,
    autoform: {
      options: function(){
        return [
          {label: "Inspection", value: "inspection"},
          {label: "Service", value: "service"}
        ];
      }
    }
  },

  'TasksWithData.$.inspectionDetails.$.startDate': {
    type: Date,
    label: "Start Date/Time",
    optional: true,
    autoform: {
      afFieldInput: {
        type: "bootstrap-datetimepicker"
      }
    }
  },

  'TasksWithData.$.inspectionDetails.$.activeTask': {
    type: Boolean,
    label: "Defer Inspection",
    defaultValue: false, //not added by default
    optional: true,
    autoform: {
      type: "boolean-checkbox"
    }
  },

  'TasksWithData.$.inspectionDetails.$.activeTask': {
    type: Boolean,
    label: "Complete",
    defaultValue: true, //not added by default
    optional: true,
    autoform: {
      type: "boolean-checkbox"
    }
  },

  'TasksWithData.$.inspectionDetails.$.desc': {
    type: String,
    label: "Additional Details/Notes",
    optional: true,
    autoform: {
      afFieldInput: {
        type: "textarea",
        rows: 10
      }
    }
  },

  'TasksWithData.$.TaskItem': {
	  type: Array,
    optional: true,
    label: "Add Task Items",
  },

  'TasksWithData.$.TaskItem.$': {
    type: Object,
    optional: true,
  },

  'TasksWithData.$.TaskItem.$.DataFacilitySection': {
    type: String,
    label: "Add a Facility Section",
    optional: true,
    autoform: {
      firstOption: 'Choose a Section',
      options: function() {
        return TemplateSectionsData.find({}, {
          sort: {
            sectionName: 1,
          }
        }).map( function ( c ){
          return{
            label: c.sectionName,
            value: c.sectionName
          };
        });
      }
    }
  },

  'TasksWithData.$.TaskItem.$.DataItemDescription': {
    type: String,
    label: "Add a Title",
    optional: true,
    autoform: {
      firstOption: 'Choose a Title',
      options: function() {
        return TemplateItemsData.find({}, {
          sort: {
            itemDescription: 1,
          }
        }).map( function ( c ){
          return{
            label: c.itemDescription,
            value: c.itemDescription
          };
        });
      }
    }
  },

  'TasksWithData.$.TaskItem.$.DataItemSection':{
    type: String,
    label: "Add a Section",
    optional: true,
    autoform: {
      firstOption: 'Choose a Section',
      options: function() {
        return TemplateItemsData.find({}, {
          sort: {
            itemSection: 1,
          }
        }).map( function ( c ){
          return{
            label: c.itemSection,
            value: c.itemSection
          };
        });
      }
    }
  },

  'TasksWithData.$.TaskItem.$.DataItemCode': {
    type: String,
    label: "Add a Code",
    optional: true,
    autoform: {
      firstOption: 'Choose a Code',
      options: function() {
        return TemplateItemsData.find({}, {
          sort: {
            itemCode: 1,
          }
        }).map( function ( c ){
          return{
            label: c.itemCode,
            value: c.itemCode
          };
        });
      }
    }
  },

  'TasksWithData.$.TaskItem.$.DataLink': {
    type: String,
    label: "External Link",
    optional: true
  },

  'TasksWithData.$.TaskItem.$.DataItemPass': {
    type: Boolean,
    label: "Pass or Fail",
    optional: true,
    defaultValue: true,
    autoform: {
      template: "custom",
      afFieldInput: {
        type: "boolean-radios",
        trueLabel: "Pass",
        falseLabel: "Fail"
      }
    }
  },

  'TasksWithData.$.TaskItem.$.DataWarning': {
    type: Boolean,
    label: "Warning",
    optional: true,
    defaultValue: null,
    autoform: {
      template: "custom",
      afFieldInput: {
        type: "boolean-checkbox",
      }
    }
  },


  'TasksWithData.$.Certification': {
	  type: Array,
    optional: true
  },

  'TasksWithData.$.Certification.$': {
	  type: Object,
    optional: true
  },

  'TasksWithData.$.Certification.$.Certified': {
    type: Boolean,
    optional: true,
    label: "Certified Decals Dated and Applied as Required?",
    defaultValue: null,
    autoform: {
      afFieldInput: {
        type: "boolean-checkbox"
      }
    }
  },

  'TasksWithData.$.Certification.$.ReasonNotApplied': {
    type: String,
    optional: true,
    label: "Reason Not Applied",
    autoform: {
      initialCount: 0,
      maxCount: 1,
      afFieldInput: {
        type: "textarea",
        rows: 8
      }
    }
  },

  'TasksWithData.$.author': {
    type: String,
    label: "Author",
    optional: true,
    autoValue: function() {
      return this.userId
    },
    autoform: {
      type: "hidden"
    }
  }

});

ClientData.attachSchema( ClientDataSchema );

I believe that autoform might be trying to save the the field DataItemPass at the top level in the document instead of as a child deep inside the document, which is why SimpleSchema complains of it not being allowed in the schema.

If I were you I would write this DataItemPass form by hand instead of using autoform.