Mohan pd.
Mohan pd. Author of The Coders Blog. Also a professional fullstack javascript developer working with various tech company and client around world.

Integrating Uniforms in Meteor app with React JS

Sep 04, 2019 · 4 minutes
Integrating Uniforms in Meteor app with React JS

While I was trying to implement uniforms, ReactJS Component package for handling form, in one of my project which use Meteor Framework and ReactJS as view engine, integration was tricky and most document are outdated. After few attempt, I solve it and decided to write a blog.

In this article, without wasting time, I will go through step by process to install uniforms and implement it.

So let’s start, first uniforms has support for popular css framework like bootstrap, semantic-ui etc. It can also be implemented without using any of those css framework. But for this article we will use semantic ui. So let’s go step by step:

Installing Required Dependencies

 meteor npm i --save uniforms
 meteor npm i --save uniforms-semantic
 meteor npm i --save uniforms-bridge-simple-schema-2
 meteor npm i --save simpl-schema

Use simpl-schema rather then aldeed/simple-schema-js which won’t work but is suggested by other old guide.

Now, we will create a simple mongo collection in import/api folder. Let’s sayProducts.js which will contain a simple collection declaration statement and a simple schema for the collection.

Creating Simple Schema & Collection

import { Mongo } from "meteor/mongo";
import SimpleSchema from "simpl-schema";
import { Tracker } from "meteor/tracker";

Meteor.methods({
  "products.insert": function(data) {
    Products.insert({ ...data, createdAt: Date.now() });
  }
});

Products = new Mongo.Collection("products");

ProductSchema = new SimpleSchema(
  {
    productName: {
      type: String
    },
    price: {
      type: String,
      optional: true
    },
    color: {
      type: String,
      optional: true
    },
    brand: {
      type: String,
      optional: true
    },
    productDescription: {
      type: String,
      max: 400
    },
    productImage: {
      type: String,
      optional: true
    },
    productDescription: {
      type: String,
      optional: true
    },
    productCategory: {
      type: String,
      optional: true,
      allowedValues:["Electronics", "Automobile"]
    },
    productYear: {
      type: Number,
      optional: true
    },
    priceNegotiable: {
      type: Boolean,
      optional: true
    },
    conditions: {
      type: String,
      optional: true
    },
    userFor: {
      type: Number,
      optional: true
    },
    homeDeliveryOptions: {
      type: String,
      optional: true,
      allowedValues:["Yes", "No"]
    }
  },
  { tracker: Tracker }
);

Products.attachSchema(ProductSchema);

export { ProductSchema, Products }

In the above code, tracker:Tracker is passed toSimpleSchema constructor. Moreover,attachSchema prototype is used from Products object to attached schema to collection declaration. We are done in api/import folder. Also, don’t forget to export the schema and collection.

Wherever uniforms AutoForm component is used, it is necessary to import ` uniforms-bridge-simple-schema-2 package.

Let, create a ` ProductForm component inimports/ui folder so that.

Creating a Simple Form Component

import React from "react";
import { Meteor } from "meteor/meteor";
import AutoForm from "uniforms-semantic/AutoForm";
import TextField from "uniforms-semantic/TextField";
import LongTextField from "uniforms-semantic/LongTextField";
import SelectField from "uniforms-semantic/SelectField";
import NumField from "uniforms-semantic/NumField";
import SubmitField from "uniforms-semantic/SubmitField";
import { Form } from "semantic-ui-react";
import "uniforms-bridge-simple-schema-2";

import { ProductSchema } from "../../api/products.js";

export default function ProductForm({ model = undefined }) {
function submit(data, formRef) {
  Meteor.call("products.insert", data, err => {
    if (err) {
      console.log(err);
      // Necessary code for handling error is written here.
      return;
    } else {
      // this code will clear all the value in the form.
      formRef.clear;
      // Necessary code after success is written here.
      return;
    }
  });
}
  return (
    <AutoForm
      ref={ref => {
        fRef = ref;
      }}
      schema={ProductSchema}
      onSubmit={data => submit(data, fRef, modal)}
    >
      <Form.Field>
        <Form.Group widths="equal">
          <TextField
            name={"productName"}
            showInlineError={true}
            placeholder="Enter Product Name"
          />
          <TextField
            name={"price"}
            showInlineError={true}
            placeholder="Enter Product Price"
          />
        </Form.Group>
        <Form.Group widths="equal">
          <TextField
            name={"color"}
            showInlineError={true}
            placeholder="Enter Product color"
          />
          <TextField
            name={"brand"}
            showInlineError={true}
            placeholder="Enter Product brand"
          />
        </Form.Group>
        <Form.Group widths="equal">
          <LongTextField
            name={"productDescription"}
            showInlineError={true}
            placeholder="Enter Product Description"
          />
        </Form.Group>
      </Form.Field>
      <Form.Field>
        <Form.Group widths="equal">
          <SelectField name={"productCategory"} showInlineError={true} />
          <TextField
            name={"productYear"}
            showInlineError={true}
            placeholder="Enter manufactured year"
          />
        </Form.Group>
      </Form.Field>
      <Form.Field>
        <Form.Group widths="equal">
          <LongTextField
            name={"conditions"}
            showInlineError={true}
            placeholder="Product Condition"
          />
        </Form.Group>
      </Form.Field>
      <Form.Field>
        <Form.Group widths="equal">
          <NumField name={"userFor"} showInlineError={true} />
          <SelectField name={"homeDeliveryOptions"} showInlineError={true} />
        </Form.Group>
      </Form.Field>
      <SubmitField />
    </AutoForm>
  );
}

In the above code, we have used AutoForm component. As a children, we have implement some component from semantic-ui-react (might need to install it if you haven’t :D) and some component form uniforms-semantic to generate a decent looking form. Furthermore, we have passed onSubmit function to user input values when user submit a form.

Passing showInLineError props as true will show error just below the relevant form input field.

Let’s look at the submit function, as it receive two parameter, data & formRef. Moving forward, early in Products.js we have also declared Meteor method which save data to db which is define as product.insert just after declaring mongo collection. Now, we are going to call the same method as passing the data object.

function submit(data, formRef) {
  Meteor.call("products.insert", data, err => {
    if (err) {
      console.log(err);
      // Necessary code for handling error is written here.
      return;
    } else {
      // this code will clear all the value in the form.
      formRef.clear;
      // Necessary code after success is written here.
      return;
    }
  });
}

formRef.clear is used to clear the form after successfully submission. Also, there are other way to handle form reset it is just one way.

In conclusion, schema and its validation rules need define the error message and they can be customized. For further reading refer simpl-scheme docs.