2
votes

I'm having trouble adding new nested/array values to a collection using autoForm.

I'm trying to use a quickForm to update questions. I'd like the user to be able to add more answer options. My schema looks like this (simplified to omit order, some metadata, etc):

questionSchema = new SimpleSchema({
  label: {
    type:   String
  },
  answers: {
    type: Array,
    minCount: 2,
    maxCount: 6
  },
  "answers.$": {
    type: Object
  },
  "answers.$._id": {
    type: String,
    regEx: SimpleSchema.RegEx.Id,
    autoValue: function(){ return Random.id(); },
    autoform: {
      type: "hidden"
    }
  },
  "answers.$.label": {
    type: String,
    regEx: /.{1,150}/,
    autoform: {
      label: false
    }
  },
  "answers.$.count": {
    type: Number,
    defaultValue: 0,
    autoform: {
      type: "hidden"
    }
  }
});

Other than answers.$.label, I was not using any autoform options when I was just adding questions via a quickForm type='insert'. I added those options when I wanted to edit questions because otherwise I got a complaint that I'd left count null. So I made them hidden but let them be in the form.

My edit form looks like this:

{{> quickForm collection="Questions" id="editQuestionForm"
    type="update" setArrayItems="true" doc=questionToEdit
    fields="label, answers"}}

I'm currently able to update the labels for my question and any answers that I initially added. But I can't add new answer options. When I do that, it's denied because count is not optional. But I specified a defaultValue...

I would rather my quickForm look like this so that I'm not putting the counts or _ids where the user could change them:

{{> quickForm collection="Questions" id="editQuestionForm"
    type="update" setArrayItems="true" doc=questionToEdit
    fields="label, answers, answers.$.label"}}

But maybe I need to keep answers.$._id there and hidden to ensure my changes update the right answers?

So:

  1. My answer counts default to 0 on insert, so why doesn't that happen when I edit and add answers?

  2. Can autoForm do an upsert instead of an update? Insert new questions, update existing question labels, use defaultalue or autoValue as needed.

  3. Should I use a method for this type of thing?

1
There are a couple possibilities. The first thing I want to know is what are you doing with the count property? Is it supposed to increment for each new addition (so that you could, eg, index that arbitrary starting order)? --BUT: It could be as simple as omitFields="'answers.$._id','answers.$.count'", instead of a fields propertypfkurtz
The count property is only updated by a client device so I just want it to start at 0 if I add answers. If I add the omitFields I still get "Count is required" for the initial answers when I try to update the question.roblingle
Also, I'm only allowing users to update questions that have answer counts of 0 across the board, so I've considered using a before update hook to ensure all counts are 0, and leave _id in the form and hidden.roblingle
If I make count optional, things almost sort of work. The _id is actually put into the id of the inputs on the form, so that seems ok. If I add answers, they get _ids, but all of the count properties are removed and the new answer doesn't get one either... So, again, I could use a before update hook but that seems like a hack and it wouldn't work with nested arrays where I did not want to reset attributes.roblingle

1 Answers

2
votes

EDIT: I've updated the example and deployed the test app to metoer at http://test-questions.meteor.com/. Its a bit rough around the edges (to be honest, it's anything but useful) but it should show the functionality in action. Use the add a new question link at the bottom. The existing questions should show up at the bottom of addquestion form. Click an existing question to edit it. Overall, the functionality is there. Just don't hate me for bad design. Blame the goddess of time.


The way I usually do embedded docs is by dividing each sub object into a separate schema. This keeps the code tidy and easier to understand as well as to avoid typical pitfalls.

Here a sample project demonstrating the below shema in action. Just git pull and meteor run: https://github.com/nanlab/question


new link http://app-bj9coxfk.meteorpad.com/

Code: http://meteorpad.com/pad/7fAH5RCrSdwTiugmc/


question.js:

Questions = new Mongo.Collection("questions");

SimpleSchema.answerSchema = new SimpleSchema({
    _id: {
        type: String,
        regEx: SimpleSchema.RegEx.Id,
        autoValue: function() {
            return Random.id();
        },
        autoform: {
            type: "hidden"
        }
    },
    label: {
        type: String,
        regEx: /.{1,150}/,
        autoform: {
            label: false
        }
    },
    count: {
        type: Number,
        autoValue: function() {
            return 0;
        },
    }
})

Questions.attachSchema(new SimpleSchema({
    label: {
        type: String
    },
    answers: {
        type: [SimpleSchema.answerSchema],
        minCount: 2,
        maxCount: 6
    },
}))


Questions.allow({
  insert: function(){return true;},
  update: function(){return true;},
})


if(Meteor.isServer) {
    Meteor.publish("questions", function() {
        return Questions.find();
    })
} else {
    Meteor.subscribe("questions");
}