Pages

Wednesday, July 20, 2016

Learning Meteor.js [Part 37]: Use SimpleSchema to run validation and show errors on the client

On my previous post I went over how to handle server errors in a central place. That works for the two main cases:
  1. If the data fails validation on the client, the error is shown without even going to the server.
  2. If the data passes validation on the client but fails some business rule on the server, an error is shown.
Due to latency compensation the user immediately sees the changes locally instead of having to wait for the server's response. For the most part this works perfectly, however one limitation is that when an error is triggered there is no way to know if it failed by the client's validation or the server's validation. I ran into this problem with a feature that had a modal dialog: if the data failed validation on the client I wanted to show an error and keep the modal up. If it passed, I wanted to hide the modal immediately while the server method was called.

Luckily this can be achieved by using the SimpleSchema package directly. First, the schema must be exported so that it can be used by both the ValidatedMethod and on the client:
export const IngredientSchema = new SimpleSchema({
    name: { type: String },
    imageUrl: { type: String, optional: true }
});

Then, on the client you can use it to run validation and display errors:
import { IngredientSchema } from '../../api/ingredients/ingredients.js';
import * as IngredientMethods from '../../api/ingredients/ingredients.methods.js';

Template.ingredientsListPart.events({
    'click .ingredient-save': function(event, template) {
        var validationContext = IngredientSchema.namedContext();
        var newIngredient = IngredientSchema.clean({
            name: $('#inputIngredientName').val(),
            imageUrl: $('#inputIngredientImageUrl').val()
        });

        if(!validationContext.validate(newIngredient)) {
            // invalid ingredient, stay on modal and show error
            var errorObj = validationContext.getErrorObject();
            template.addIngredientError.set(errorObj.message);
        } else {
            // dismiss modal and call server.
            $('#addIngredientModal').modal('hide');
            IngredientMethods.addOrUpdate.call({ ingredient: newIngredient }, methodReturnHandler);
        }
    }
});

Notice that IngredientSchema.clean() is called before validate(). This will run the same data clean up that is run on the server as I described on this post. After you validate the data any errors are available on the validation context, which you can use to update the UI.

You can check the code up to this point by using this commit or visit the live demo.



No comments:

Post a Comment

Note: Only a member of this blog may post a comment.