Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using objects as options in Autoform

In my Stacks schema i have a dimensions property defined as such:

dimensions: {
    type: [String],
    autoform: {
        options: function() {
            return Dimensions.find().map(function(d) {
                return { label: d.name, value: d._id };
            });
        }
    }
}

This works really well, and using Mongol I'm able to see that an attempt to insert data through the form worked well (in this case I chose two dimensions to insert)

Mongol image

However what I really what is data that stores the actual dimension object rather than it's key. Something like this:

[Mongol good[2]

To try to achieve this I changed type:[String] to type:[DimensionSchema] and value: d._id to value: d. The thinking here that I'm telling the form that I am expecting an object and am now returning the object itself.

However when I run this I get the following error in my console.

Meteor does not currently support objects other than ObjectID as ids

Poking around a little bit and changing type:[DimensionSchema] to type: DimensionSchema I see some new errors in the console (presumably they get buried when the type is an array

console image

So it appears that autoform is trying to take the value I want stored in the database and trying to use that as an id. Any thoughts on the best way to do this?.

For reference here is my DimensionSchema

export const DimensionSchema = new SimpleSchema({
    name: {
        type: String,
        label: "Name"
    },
    value: {
        type: Number,
        decimal: true,
        label: "Value",
        min: 0

    },
    tol: {
        type: Number,
        decimal: true,
        label: "Tolerance"
    },
    author: {
        type: String,
        label: "Author",
        autoValue: function() {
            return this.userId
        },
        autoform: {
            type: "hidden"
        }
    },
    createdAt: {
        type: Date,
        label: "Created At",
        autoValue: function() {
            return new Date()
        },
        autoform: {
            type: "hidden"
        }
    }
})
like image 635
Chris Avatar asked Aug 06 '16 17:08

Chris


1 Answers

According to my experience and aldeed himself in this issue, autoform is not very friendly to fields that are arrays of objects.

I would generally advise against embedding this data in such a way. It makes the data more difficult to maintain in case a dimension document is modified in the future.

alternatives

  • You can use a package like publish-composite to create a reactive-join in a publication, while only embedding the _ids in the stack documents.
  • You can use something like the PeerDB package to do the de-normalization for you, which will also update nested documents for you. Take into account that it comes with a learning curve.
  • Manually code the specific forms that cannot be easily created with AutoForm. This gives you maximum control and sometimes it is easier than all of the tinkering.

if you insist on using AutoForm

While it may be possible to create a custom input type (via AutoForm.addInputType()), I would not recommend it. It would require you to create a template and modify the data in its valueOut method and it would not be very easy to generate edit forms.

Since this is a specific use case, I believe that the best approach is to use a slightly modified schema and handle the data in a Meteor method.

Define a schema with an array of strings:

export const StacksSchemaSubset = new SimpleSchema({
  desc: {
    type: String
  },
  ...
  dimensions: {
    type: [String],
    autoform: {
      options: function() {
        return Dimensions.find().map(function(d) {
            return { label: d.name, value: d._id };
        });
      }
    }
  }
});

Then, render a quickForm, specifying a schema and a method:

<template name="StacksForm">
  
  {{> quickForm
    schema=reducedSchema
        id="createStack"
        type="method"
        meteormethod="createStack"
        omitFields="createdAt"
  }}

</template>

And define the appropriate helper to deliver the schema:

Template.StacksForm.helpers({
  reducedSchema() {
    return StacksSchemaSubset;
  }
});

And on the server, define the method and mutate the data before inserting.

Meteor.methods({
  createStack(data) {
    // validate data
    const dims = Dimensions.find({_id: {$in: data.dimensions}}).fetch(); // specify fields if needed
    data.dimensions = dims;
    Stacks.insert(data);
  }
});
like image 53
MasterAM Avatar answered Oct 09 '22 04:10

MasterAM