Schema validation errors not showing in AutoForm

Based on the AutoForm and Collection2 documentation, I’m under the impression that schema validation errors should be shown to the user automatically by AutoForm (error message plus highlight the bad field.) This isn’t happening for me. I get no user feedback at all. Defining an onError handler with an alert works but is pretty crude from a UI perspective.

Am I doing something wrong or am I just under a false impression?

I have the following form built with AutoForm to update some custom values in Meteor.users. I’m using afQuickFields rather than QuickForm because I want a different layout than QuickForm provides.

.html

<template name="updateProfileForm">
    {{#autoForm id="updateProfileForm" collection="Meteor.users" doc=currentUser type="update"}}
   <div class='row'>
    <div class='col-md-4'>
      {{> afQuickField name="wraithnotes.firstName" label='First Name'}}
    </div>
  </div>
  <div class='row'>
    <div class='col-md-4'>
      {{> afQuickField name="wraithnotes.lastName" label='Last Name'}}
    </div>
  </div>
  <div class="row">
     <div class="col-md-2">
       {{> afQuickField name="wraithnotes.POLInterval" label="POL Interval (days)"}}
   </div>
  </div>
  <div>
    <button type="submit" class="btn btn-primary">Submit</button>
    <button type="reset" class="btn btn-default">Reset</button>
  </div>
   {{/autoForm}}
 </template>

schema.js

Schemas.wraithnotes = new SimpleSchema({
    POLInterval: {
        type: SimpleSchema.Integer,
        min: 10,
        max: 999,
        optional: true
    },
    firstName: {
        type: String,
        regEx: /^[a-zA-Z-]{2,25}$/,
        optional: true,
    },
    lastName: {
        type: String,
        regEx: /^[a-zA-Z]{2,25}$/,
        optional: true,
    },
 });

.js

AutoForm.hooks({
  updateProfileForm: {
    onError: function(formType, error) {
      alert(error.message);
      console.log("onError:", error.message, "formType:", formType);
      console.log("validation context:", AutoForm.getValidationContext(this.formId));
    }
  }
});

If I submit the form with a bad value (setting POLInterval to 9999 for instance) the onError function is called and an alert pops up. but the field isn’t hightlighted and no error is displayed on the form.

2 Likes

Have another look at the docs for the collection and schema options.

Also, give this a shot:

  1. Add a schema option to the autoForm and set it to Schemas.wraithnotes.
  2. Do away with the dotted field references, e.g. firstName instead of wraithnotes.firstName.

Thanks for the suggestions @mattl but…

  1. I don’t need a schema option because Schemas.wraithnotes is attached to the Meteor.users collection. Adding a schema option (or replacing collection with one) causes AutoForm to throw internal errors.

  2. My bad attempt at simplifying my code for the post. In reality wratihnotes is part of Meteor.users (which is the collection I passed in) so the dotted notations are correct. The form displays correctly and updates correctly if none of the fields are in error. Only the display of error messages is “broken”. If anyone thinks that the problem lies in the schema I can post the entire thing instead, but I don’t think the problem is there since display and update work fine.

I see. I thought that you might be attempting to override the collection schema. It’s hard to say what the issue is without seeing all of the code but, typically, these types issues are easy to resolve once the source of the problem is found.

Yeah, I’m probably either not doing something I should or just doing
something stupid. I’m going to try extracting the pertinent code into a
new project to see if I can reproduce the problem with a smaller code
base. I’ll follow up with results.

Sorry for digging but any followup? This looks like similar problem to mine - I can’t get my quickFields to display error message under them event though validation works fine and after submitting form with obvious errors the first control with error gets focus.

1 Like

Make sure you put {tracker: Tracker} at the end

Schemas.wraithnotes = new SimpleSchema({
    POLInterval: {
        type: SimpleSchema.Integer,
        min: 10,
        max: 999,
        optional: true
    },
    firstName: {
        type: String,
        regEx: /^[a-zA-Z-]{2,25}$/,
        optional: true,
    },
    lastName: {
        type: String,
        regEx: /^[a-zA-Z]{2,25}$/,
        optional: true,
    },
 }, {tracker: Tracker});
4 Likes

Adding that to the schema makes no difference. Still no error message.

1 Like

A year later, same problem for me… have you a solution plz .?

I never solved the problem, I moved on to writing code for new features instead. But it is probably time to loop back around and see if I can figure it out. I’ll take a stab at it this week once I get the 1.7 changes made. I’m on Windows 10, so Meteor is broken for me without the symlink fix which is in 1.7-rc.11.

Adding that tracker thing fixed it for me. My schema is not database backed - although I doubt that is relevant.

1 Like

I am in the process to upgrade a project to the latest version of autoform/collection2/simpl-schema and have the same problem, nested schemas do not show the validation errors

1 Like

I just solved it by creating the following onError hook for my nested schema autoform

AutoForm.hooks({
  idOfTheForm: {
    beginSubmit(insertDoc, updateDoc, currentDoc) {
      const af = this;
      // clear old errors
      Meteor.defer(function(){
        af.template.findAll('div.form-group.has-error').forEach((parent) => {
          parent.classList.remove('has-error');
          var help = parent.querySelector('.help-block');
          if(help) help.textContent = "";
        });
      })
    },
    onSuccess(formType, result){
      console.log(this);
    },
    onError(formType, error) {
      const af = this;
      console.error(error);
      // wait for Blaze to have everything rendered
      Meteor.defer(function(){
        // iterate over validationErrors
        for (let ve of af.validationContext._validationErrors) {
          // find the form element
          var el = af.template.findAll(`[data-schema-key="${ve.name}"]`);
          if (el.length > 0) {
            // the parent is the form-group
            var parent = el[0].parentNode;
            // add has-error class
            parent.classList.add('has-error');
            // get help-block and control-label
            var help = parent.querySelector('.help-block');
            var label = parent.querySelector('.control-label');
            // set the help-block text if it is empty
            if (help) {
              var c = help.textContent;
              if(!c) help.textContent = `${label.textContent} required`;
            }
          }
        }
      })
    },
  }
});

2 Likes

Thanks @jamgold! This is the only way I could get any errors to display!

  • correction in onError(),.control-label is on the grandparent class of el;
  • Also added the ability to display a message that a custom error could have returned:
      onError(formType, error) {
        const af = this;
        console.error(error);
        // wait for Blaze to have everything rendered
        Meteor.defer(function handleErrs() {
          // iterate over validationErrors
          for(let ve of af.validationContext._validationErrors) {
            // find the form element
            let el = af.template.findAll(`[data-schema-key="${ve.name}"]`);
            if(el.length > 0) {
              // the parent is the form-group
              let parent = el[0].parentNode;
              // add has-error class
              parent.classList.add('has-error');
              // get help-block and control-label
              let help = parent.querySelector('.help-block');
              let gParent = parent.parentNode;
              let label = gParent.querySelector('.control-label');
              // set the help-block text if it is empty
              if(help) {
                let c = help.textContent;
                if(!c) help.textContent = error.message || `${label.textContent} required`;
              }
            }
          }
        });
      }

PS: I think this code is a much simpler version of using the HTML technique here.

1 Like

I just ran into this issue too. Happens to me in both quickForm and autoForm. Thanks for this awesome work-around. With 500+ open issues, hopefully the community jumps in and gives this package some love.

We just upgraded AutoForm to 6 and also SimpleSchema to use the npm version. It’s been a bit of a pain TBH. The major issue we have is this one, showing validation errors for subschemas. We do manual validation so using the hooks wasn’t an option so I took @jamgold’s code and created two functions.

export function removeValidationErrors(template) {
    template.findAll("div.form-group.has-error").forEach(parent => {
        parent.classList.remove("has-error");
        let help = parent.querySelector(".help-block");
        if (help) {
            help.textContent = "";
        }
    });
}

export function displayValidationErrors(template, formId) {
    const vc = AutoForm.getValidationContext(formId);
    for (let ve of vc._validationErrors) {
        // find the form element
        let el = template.findAll(`[data-schema-key="${ve.name}"]`);
        if (el.length > 0) {
            // the parent is the form-group
            let parent = el[0].parentNode;
            // add has-error class
            parent.classList.add("has-error");
            // get help-block and control-label
            let help = parent.querySelector(".help-block");
            let gParent = parent.parentNode;
            let label = gParent.querySelector(".control-label");
            // set the help-block text if it is empty
            if (help) {
                let c = help.textContent;
                if (!c) {
                    help.textContent = `${label.textContent} required`;
                }
            }
        }
    }
}

Our submit event then looks like this:

 "click #button": function(event, template) {
        removeValidationErrors(template);
        const valid = AutoForm.validateForm(template.formId);
        if (valid) {
            const values = AutoForm.getFormValues(template.formId);
            //do stuff
        } else {
            displayValidationErrors(template, template.formId);
        }
     }

This works although it’s not 100% satisfactory as when the user starts typing after an error it doesn’t automatically validate it again so we have to add.

    "keypress #field-that-could-fail1, keypress #field-that-could-fail2": _.debounce(
        function(event, template) {
            removeValidationErrors(template);
            displayValidationErrors(template, template.formId);
        },
        100,
        {leading: false}
    )

As it seems we’ll have an AF7 soon - see . I might wait and see if we can fix it there. I tried debugging the code and the validation errors are definitely found, it just fails to add the help-blocks to the DOM. Has anyone here spotted where it fails exactly ? If we could get the community version published soon and this fixed I think it’ll be a big boost for all of us.

I think I found the cause. Here’s the issue

So if anyone is interested here’s how you can fix this.

meteor npm i https://github.com/lynchem/simple-schema-js/tarball/package-in-root --save

In your package.json you’ll need

"meteor": {
   "nodeModules": {
        "recompile": {
            "simpl-schema": true
         }
    }
}

I had to modify the original package to put package.json in the root as npm install still doesn’t support subdirectories.

1 Like