Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow removing sticky errors outside of hooks #805

Closed
mologie opened this issue Mar 21, 2015 · 6 comments
Closed

Allow removing sticky errors outside of hooks #805

mologie opened this issue Mar 21, 2015 · 6 comments

Comments

@mologie
Copy link

mologie commented Mar 21, 2015

Hello,

the documentation for sticky form errors states that

The sticky error will go away when the form is reset (such as after a successful submission)

This does not seem to be working correctly. The form is never submitted while there are sticky validation errors, though the documentation implies that sticky errors should not prevent form submission. I am using AutoForm to model a login form as follows:

var loginSchema = new SimpleSchema({
    username: {
        type: String,
        label: "Username"
    },
    password: {
        type: String,
        label: "Password"
    }
});

SimpleSchema.messages({
    "invalid-username": "Invalid username",
    "invalid-password": "Invalid password"
});

Template["login"].rendered = function () {
    AutoForm.resetForm("loginForm");
    this.$("input[name=username]").select();
};

Template["login"].helpers({
    loginSchema: function () {
        return loginSchema;
    }
});

AutoForm.addHooks("loginForm", {
    onSubmit: function (doc) {
        console.log("AutoForm submit");

        Meteor.loginWithPassword(doc.username, doc.password, (err) => {
            if (err) {
                // XXX meteor does not provide a reliable method for detecting the error type
                var incorrectUserName = (err.message == "User not found [403]");
                var incorrectPassword = (err.message == "Incorrect password [403]");

                if (incorrectUserName) {
                    this.addStickyValidationError("username", "invalid-username");
                    AutoForm.validateForm("loginForm"); // XXX see AutoForm bug 755
                }
                else if (incorrectPassword) {
                    this.addStickyValidationError("password", "invalid-password");
                    AutoForm.validateForm("loginForm"); // XXX see AutoForm bug 755
                }
                else {
                    alert("Unknown authentication error: " + err.message);
                }
                this.done(err);
            }
            else {
                this.done();
            }
        });
        return false;
    },
    onError: function () {
        console.log("AutoForm error");
    }
});
<template name="login">
    <div class="container form-container">
        <h1>Login</h1>
        {{#autoForm id="loginForm" schema=loginSchema}}
            {{> afQuickField name="username"}}
            {{> afQuickField name="password" type="password"}}
            <div class="form-group">
                <button type="submit" class="btn btn-primary btn-lg action-login" id="login-button" data-loading-text="Logging in...">Login</button>
            </div>
        {{/autoForm}}
    </div>
</template>

When hitting the login button, the debug console (Google Chrome) displays "AutoForm submit" once, and "AutoForm error" in all subsequent submission attempts.

Thanks,
Oliver

@aldeed
Copy link
Collaborator

aldeed commented Mar 21, 2015

They do prevent form submission. That is the point of them. The bit about going away when the form is reset just means that they'll disappear if you have a reset button and the user clicks it. But in order to submit successfully, you'll have to remove any sticky errors you've added each time they submit.

In general, adding the following in a beginSubmit hook should work:

this.removeStickyValidationError('username');
this.removeStickyValidationError('password');

You may prefer to have those in a keyup or blur event handler that you attach to those input fields. Basically whenever you want that sticky error to go away. But it has to come before the onSubmit function because having sticky errors will prevent onSubmit from being called (as you found out).

Edit: Just realized they can't be in keyup/blur handler since they're only available on the hook context. Maybe we'll have to add a more general API function for removing them.

@mologie
Copy link
Author

mologie commented Mar 21, 2015

Thank you for the quick response and clarification. It looks like beforeSubmit suffers from the same fate like the onSubmit hook: It is never called if validation fails. I therefore went with the following very ugly hack, which will most likely bite me very soon:

function removeStickyValidationError(key) {
    delete AutoForm.templateInstanceForForm("loginForm")._stickyErrors[key];
    AutoForm.validateForm("loginForm");
}

Template["login"].events({
    "change input[name=username]": function () {
        removeStickyValidationError("username");
    },
    "change input[name=password]": function () {
        removeStickyValidationError("password");
    }
});

This gives me the expected behaviour.

Unrelated note for potential readers: I have also tried experimenting with non-sticky errors using the getValidationContext API. The code looked as follows:

AutoForm.getValidationContext("loginForm").addInvalidKeys([
    {name: "username", type: "invalid-username"}
]);

However, I could not get this to work reliably. AutoForm appears to validate the form at seemingly random intervals (it probably debounces DOM events in order to not cause delayed UI response). Disabling the "keyUp" validation only helped partially. Long story short, non-sticky errors do indeed not stick and tend to disappear without obvious reason.

@aldeed
Copy link
Collaborator

aldeed commented Mar 21, 2015

Your workaround is pretty similar to what we'll have to provide, and possibly also a new pre-validation hook. I had tested by clearing the sticky errors in a "before" hook, but in some cases, like when using onSubmit, that's not an option, so that's an oversight.

As far as the other approach, revalidation should be happening only on change, blur, and throttled keyup. But yes, as soon as the first revalidation occurs, you lose any manually added invalid keys. That's why the sticky keys are necessary.

@aldeed aldeed added this to the 5.0 Fixes milestone Mar 21, 2015
@outaTiME
Copy link

outaTiME commented May 6, 2015

Release date ??

@aldeed aldeed changed the title Sticky form errors prevent form submission Allow removing sticky errors outside of hooks May 7, 2015
aramk added a commit to aramk/meteor-autoform that referenced this issue May 20, 2015
* devel: (143 commits)
  bump version
  rearrange and fix Meteor-Community-Packages#831
  bump version
  Fix validation for autoForm's with no type set
  bump version
  prevalidate method type forms only when both schema and collection are provided (fix Meteor-Community-Packages#766)
  change array handling
  ignore errors due to timing (Meteor-Community-Packages#789)
  better error for missing form id; fixes Meteor-Community-Packages#776
  move beginSubmit hook call to before prevalidation (Meteor-Community-Packages#805)
  change when formToDoc is called, add formToModifier, and optimize creating doc/mod from form (Meteor-Community-Packages#816)
  Add orion to community packages
  Update autoform-api.js
  Add try/catch to _validateField method
  Add return to afOptionsFromSchema helper
  docs
  docs
  bump version
  Meteor 1.0.4 compatibility fixes (closes Meteor-Community-Packages#790; closes Meteor-Community-Packages#794)
  minor error msg change
  ...

Conflicts:
	components/autoForm/autoForm.js
@aldeed
Copy link
Collaborator

aldeed commented Oct 11, 2015

Added in 5.7.0

@aldeed aldeed closed this as completed Oct 11, 2015
@jclay
Copy link

jclay commented Aug 15, 2016

For future readers, the latest release allows you to refactor @mologie's code into:

Template["login"].events({
    "change input[name=username]": function () {
        AutoForm.removeStickyValidationError('loginForm', 'username')
    },
    "change input[name=password]": function () {
        AutoForm.removeStickyValidationError('loginForm', 'password')
    }
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants