-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
API FIX Use aria-describedby and default error element changed to span #1083
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
API FIX Use aria-describedby and default error element changed to span #1083
Conversation
Travis fails with "too many var statements"... are variables obsolete now? 🍔 I'll look at this again tomorrow. :) |
@@ -221,7 +221,7 @@ $.extend($.validator, { | |||
rules: {}, | |||
errorClass: "error", | |||
validClass: "valid", | |||
errorElement: "label", | |||
errorElement: "span", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changing the default reults in a BC break and should therefore be noted somewhere (if the BC is accepted by project owners)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed this back to label by default.
Thanks @tractorcow, this looks promising. Fixing the jshint warning should be easy enough, you can get those locally by running In #900 I wrote those:
I don't see that fully implemented here. You're always setting Even with that addressed I'm not sure how to deal with the backwards compatibility. Changed the element type would break any CSS that's based on the element name (instead of the class etc.). Maybe an intermediate step would be to keep the default option value, while doing the other changes. Anyone who knows better can set the option to |
Thanks for the feedback all! I think the API should work with existing labels, but I'll add a test to confirm this. Do you think there is any harm in consistently applying the aria-describedby? It would imagine the resulting html of the above situation appear as below; <input type="text" name="Email" id="Email" aria-describedby="Email-label" />
<label for="Email">
Email <span id="Email-label" class="error">Email is invalid</span>
</label> Also (which I think was discussed earlier) is that we need to respect existing non-error labels (as above), so we can't just assume that any label with for=elementid is an error holder. I'm not sure it's just enough to assume that label means it's the error holder, that's why I propose enforcing the aria-describedby property for all errors. Maybe I have misunderstood the use case somewhat? |
I just realised that I will need to update all of the demo/ folder files, since the default element has changed. @jzaefferer, I've updated the convention issues and added some test cases to demonstrate that this solution should work seamlessly with label elements, if the user so decides. This doesn't mean there's no breaking changes, as any users upgrading will either need to set errorElement to label or update their css / html. I suggest to merge this into a major release, if you haven't released 1.12.1 yet, and make this a part of 1.13. How does this sound? I also haven't squashed my commits; I'm not sure of the convention you prefer, if you like me to and are happy with the api changes and test cases then I'll do that. I figured that we should agree and lock down the functionality changes before I go and update the demo code, since it would be a waste of effort to rewrite them should we decide to tweak this api. :) |
Thanks for the updates. Sounds good so far, though I won't have time to check the details until next Tuesday (where I reserve a few hours each week for this plugin). As for "always applying aria-describedby": The original discussion specifically concluded with not doing that. While I haven't tried it myself either way, I suspect that in your sample, the error label would get announced twice - or run into some other issue. So we shouldn't do that. Regarding commits: I'm fine with rebasing them before I merge. Please make sure the changes itself are good though, so indent fixes should be done asap. |
Ok, well having thought about it, we can probably assume that anything with the appropriate error classes and the requisite 'for' can probably leave out the describedby attribute. I'll make a fix and submit it before the weekend. |
Thanks greatly for the feedback... I had some issues with the commitplease plugin failing with sourcetree. It was a fun morning. :) You've done some really neat things with node I must say! I've taken on your suggestion and re-implemented this so it only conditionally adds the I've also added some additional test cases to ease my fears regarding how well the error element and other related labels will work. Everything seems to play well together. :) |
What if we don't change the default just yet? We can still make the change in tests etc. (setting the option or changing the default). That way there should be no compatibility issues with the next release and we can make the switch in the future. Doesn't have to be a 2.0 as long as there's some time to adjust from communicating the change to actually landing it. |
We could :) That way we could have less breaking changes... but still change the default at a later date. It will at least solve the issue for those using spans, while no one else notices a thing. I'll go ahead and make the necessary changes. :P |
Should the bulk of the testing use the to-be-default span, or should we leave testing using the current default label? |
There is a rather frustrating bug in these test cases... testForm1clean has an error label as below. <label id="errorFirstname" for="firstname" class="error">error for firstname</label> The 'firstname' in the 'for' actually refers to the input element on another form. for only refers to elements using the name property if they are checkable... =/ Fixing this breaks heaps of the test cases, because they rely on this broken behaviour. XD Some rely on the validation rules from the other form interfering with this form. Copying the validation rules to this break others. Am I doing something wrong here? The library itself is fine... it's just the test cases not behaving well. =/ |
I also uncovered what might be a bug... but I'll have to look at this later. If an element has a data-rule-required property, then you can't use |
I've rewritten the test cases to be much less element-critical; Rather than selecting the error element by Hope the review goes well. :) Thanks for your time in helping look at this... |
@jzaefferer Hope you're doing well. :) Have you been able to look at this issue again? Sorry for needlessly bothering you; I'm just keen to get this resolved for good. :) |
var label = this.errorsFor( element ); | ||
var label = this.errorsFor( element ), | ||
place, | ||
group; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you change this to match the assignment rules in the jQuery Style Guide? http://contribute.jquery.org/style-guide/js/#assignments
var place, group,
label = ...;
(using tabs, not spaces)
The existing code has a lot of issues, but we can at least fix anything we're changing anyway.
This is starting to look pretty good, I've only found minor issues. I haven't spend enough time with the tests though, will do that after these are addressed. Let me know and I'll review again immediately. |
Thanks so much for the review @jzaefferer I've renamed the error element variable to simply "error". We probably can't rename errorsFor without breaking backwards compatibility, so I've left it as is. Style guidelines and a few more have been tidied up. Hopefully I'm learning to do things the right way! :) |
// replace message on existing label | ||
label.html(message); | ||
error.html(message); | ||
} else { | ||
// create label |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets change this, too:
// Create error element
Hey @jzaefferer I hope I've met all concerns! Now the aria-describedby doesn't appear if we are adding labels, or nesting error elements within labels. I've updated the test case to explicitly assert that the aria-describedby is not added. |
$().ready(function() { | ||
// validate the form when it is submitted | ||
var validator = $("#form1").validate({ | ||
errorLabel: 'span', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the label "span"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the error will be nested within another label, so we want to avoid labels nested within one another; It's not necessary nor good practice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't errorElement
used for that? This seems like a leftover/typo? I think we dont have a errorLabel
option in validate()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er, that's a good point. I wonder why it was working at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it works because you define errorElement
a few lines below
I've updated it again; Thanks @staabm for the feedback. |
errorPlacement: function(error, element) { | ||
// Append error within linked label | ||
$( element ) | ||
.parents( "form" ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be closest
instead? Nested forms are not that common but new browsers support them and this might lead to things you don't want here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@tractorcow thanks. @jzaefferer for my eyes this seems good to go |
Thanks @jzaefferer and @staabm for the hard work reviewing my code. It's been an educational experience for me! |
// If no describer is used then errors are either associated labels, or children of non-error labels | ||
return this | ||
.errors() | ||
.filter( "label[for='" + name + "'], label[for='" + name + "'] *" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which of the tests, new or old, covers the second branch here, the children of non-error labels
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See testForm16 in index.html. It's a new one recently added. The test has the title "test label used as error container".
Sorry to ruin the party, not quite done, yet ;) Still, I'm looking forward to landing this, I intend to release 1.13 shortly after to get it live, too. |
No problem about that, I also want this to be the best out can be. If there
|
Hey @jzaefferer, I've done as requested. Tests to do with error placement are now in error-placement.js I've done a massive amount of code-quality cleanup, both in tests and in core.js, as per the coding conventions that are in place. I've made some custom assertions and put them in test.js as below // Asserts that there is a visible error with the given text for the specified element
QUnit.assert.hasError = function( element, text, message ) {
var errors = $( element ).closest( "form" ).validate().errorsFor( element[ 0 ] ),
actual = ( errors.length === 1 && errors.is( ":visible" ) ) ? errors.text() : "";
QUnit.push(actual, actual, text, message);
};
// Asserts that there is no visible error for the given element
QUnit.assert.noErrorFor = function( element, message ) {
var errors = $( element ).closest( "form" ).validate().errorsFor( element[ 0 ] ),
hidden = ( errors.length === 0 ) || errors.is( ":hidden" ) || ( errors.text() === "" );
QUnit.push(hidden, hidden, true, message );
}; I haven't gone over ALL tests to replace these; It's just too big a task for tonight. I've demonstrated their usefulness in error-placement.js at least. I hope this is good enough to merge finally. ;) |
For your reference, I've been following the below link for style conformance. http://contribute.jquery.org/style-guide/js/ If I'm making any errors please let me know how I can follow this properly. I really hope this is acceptable. 🐱 |
This is getting quite epic. Unfortunately there's still some more work to do here:
Thanks again for all your work on this. |
Hey @jzaefferer thanks for your patience. I've fixed the assert usage and resolved the merge conflicts. |
Green tick! 🏁 |
We have a big release due next week and I'm anxious to get this included... hope that this time the review is all spot on. ;) |
yay, great job @tractorcow 👏 |
Yes, all good. Thank you! |
yay! Thanks so much @jzaefferer and @staabm too ;) |
Non-label error labels will now work correctly, with
aria-describedby
now superseding dependency on the 'for' attributeThis provides a solution to the discussion noted in #900.
A lot of work had to be done to rewrite the test cases to respect the 'span' error label... apologies if I have made any incorrect assumptions about this module.
For legacy reasons, if the error element is set as a label explicitly, it still sets the 'for' attribute, but it isn't used anywhere in the module.