This sample application illustrates how to manipulate user input using forms with Meteor 1.4, BlazeJS, and Semantic UI. This involves:
- Displaying HTML forms using the Semantic UI form classes.
- Creating a set of reusable Blaze templates for the standard form controllers, including text, textarea, checkboxes, radio buttons, and single and multiple select lists.
- Validating form data upon submission using Node Simple Schema.
- Conditional display of page content using Reactive Dictionaries.
- Inserting new documents into Mongo based upon form data, as well as retrieving and updating documents using forms.
After installing Meteor and downloading this package, cd into the apps directory and run:
meteor npm install
Next, run the system with:
meteor npm run start
That will invoke the script in the package.json to run meteor. To speed up the process, the script disables release checking.
Note regarding bcrypt warning. You will get the following message when you run this application:
On some operating systems (particularly Windows), installing bcrypt is much more difficult than implied by the above message. Bcrypt is only used in Meteor for password checking, so the performance implications are negligible until your site has very high traffic. You can safely ignore this warning without any problems.
You can also run ESLint over the source code with:
meteor npm run lint
To best understand this application, it is useful to first familiarize yourself with:
Meteor Application Template. This sample application illustrates conventions for directory layout, naming conventions, routing, integration of Semantic UI, and coding standards. Meteor-example-form is based on this template, so we won’t discuss any of these issues here.
Semantic UI Forms. Read this documentation to learn the CSS classes defined by Semantic UI to create nicely styled forms.
Validating data with Simple Schema. Actually, you’ll probably need to familiarize yourself with all of Simple Schema, but the section on data validation is crucial to understanding this sample application.
Reactive Dict, Reactive Vars, and Session Variables. This application uses Reactive Dictionaries. I found this blog posting to be a very concise and useful explanation of them and how they relate to other mechanisms like Session variables.
The home page of this application presents the Create Student Data page:
If you try pressing submit without entering any data, then validation will fail on the required fields and error messages are displayed:
After correctly filling out the form and pressing submit, the page creates an entry in the StudentData collection and provides a URL to the Update Student Data page:
Clicking on the link brings up the other page in this application, Edit Student Data, which obtains the id of a Student Data document from the URL, retrieves it from the StudentData collection, and fills out the form with this document’s fields so they can be updated:
A successful update is indicated like this:
I won’t show it here, but if you violate any validation on this update page, then it will show the same error messages as on the Create Student Data page.
Defining form validation
User input should always be validated before being further processed by the system. The canonical approach to validation in Meteor is to create a schema using Simple Schema. In this sample application, the schema is defined as part of defining the StudentData Collection.
Publications and subscriptions
Form processing using Semantic UI requires you to remove the autopublish package and to explicitly publish and subscribe to collections.
For simplicity’s sake, this example application publishes all of the StudentData collection in publications.js.
This application only needs to subscribe to the collection on the Edit Student Data page, since that’s the only page that needs to reference pre-existing StudentData. The subscription occurs in edit-student-data-page#L14.
Form controller templates
The heart of this sample application is the form-controls directory, which provides templates for implementation of the standard HTML form controls (text, textarea, checkboxes, radio buttons, and single/muliple selection drop-downs).
Consult the HTML files for documentation on how each control should be invoked and samples of the HTML code they produce. You can also see invocations of each of these templates in the edit-student-data-page and create-student-data-page.
Create Student Data
Now let’s get look at the first of the two pages: Create Student Data, and start with the HTML code.
create-student-data-page.html is the HTML template for accepting data for insertion into the StudentData collection.
It invokes controller templates to create the Name, Bio, Hobbies, Level, GPA, and Majors form controllers.
Note that create-student-data-page.html#L5 augments the “ui form” class declaration with two helpers: successClass and errorClass. These helpers return the strings “success” or “error” when the form has been successfully submitted or has been found to contain errors, respectively. Otherwise (such as when the page is first displayed), they return the empty string. So, think of the page as containing three states: “empty” (i.e. just retrieved), “success” (the form data was just submitted and there were no errors), or “error” (the form data was submitted and errors were found).
create-student-data-page.js#L11-L18 defines the constants hobbyList, levelList, majorList, and GPAObjects. These constants are exported so that this data can be also used in the edit-student-data-page.
create-student-data-page.js#L21-L26 shows the onCreated handler. This handler sets up a Reactive Dictionary to hold displaySuccessMessage, indicating if we want to display the success message, and displayErrorMessages, indicating if we want to display one or more error messages. Note that they are initialized to false, indicating that we are in the third state (neither success nor failure).
create-student-data-page.js#L28-L55 shows the helper functions for this page. They alter the appearance of the page through reactive variables (either through the messageFlags reactive dict or through the reactive variables created by the Simple Schema validation mechanism).
create-student-data-page.js#L58-L96 shows the events callback for handling the submit button event. As is usual in Meteor event processing, the first thing is to disable the default event handling. The subsequent code extracts form values from the various input types: text fields, text areas, checkboxes, radio buttons, single selection, and multiple selection. After this, the handler creates an object called newStudentData that gathers together these values.
This object is “cleaned” manually in order to make it correspond to the same object that will be checked by the Collection2 hook function as part of the insert process. Finally, we validate the form data and set the reactive variables appropriately. Note that changing the reactive variable values is all that is needed to cause the page contents to be updated.
Edit Student Data
In the HTML code, edit-student-data-page#L3 shows the first difference: the use of the Template.subscriptionsReady to delay the display of the page until the data is available.
edit-student-data-page#L21-L61 shows the implementation of the helper functions to provide values into the form. Note that these helper functions implement the Meteor “guard” design pattern to prevent fields from being accessed when the associated object is not available.
Finally, the submit event handler is just like the one in Create Student Data, except for Line 105 which calls update rather than insert.
Click the image below to watch a 19 minute walkthrough of this system.
This sample application includes the insecure package. In production settings, you will need to create Meteor methods and invoke them in the submit event handlers rather than calling the insert and update operations directly.