Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

bug(ngAria): native controls fire a single click event #10766

Closed

Conversation

marcysutton
Copy link
Contributor

To fix the widespread accessibility issue of ngClick on divs, ngAria dynamically binds keypress in addition to tabIndex. As first implemented, this introduced a bug where <button> elements would have both events bound, causing multiple callbacks to fire. This PR makes limits the addition of keypress to <div> and <li>, which can be overridden with the bindKeypress config option.

Closes #10388. Thanks to @caitp for the help & unit test on native elements.

@@ -83,7 +83,8 @@ function $AriaProvider() {
ariaMultiline: true,
ariaValue: true,
tabindex: true,
bindKeypress: true
bindKeypress: true,
keypressEls: ['DIV', 'LI']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather trivial and probably a matter of personal style, but I would prefer a non- abbreviated name (keypressElements, keypressNodeNames etc).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like keypressNodeNames. I've changed it to that. Thanks for the suggestion!

@marcysutton
Copy link
Contributor Author

@caitp this is ready for another review.

@@ -526,6 +538,31 @@ describe('$aria', function() {
element.triggerHandler({ type: 'keypress', keyCode: 13 });
expect(element.text()).toBe('keypress13');
});

it('should not bind keypress to non-div elements', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to note in the spec title that this is a symptom of using the default config. (This might be spelled out clearly higher up, can't tell on mobile view)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I've updated it.

@caitp
Copy link
Contributor

caitp commented Jan 21, 2015

Still LGTM

@@ -83,7 +83,8 @@ function $AriaProvider() {
ariaMultiline: true,
ariaValue: true,
tabindex: true,
bindKeypress: true
bindKeypress: true,
keypressNodeNames: ['DIV', 'LI']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still kind of feel like this is a really weird API. Chances are, you're going to want emulated clicks for any element that doesn't produce them on their own, right? if this array gets out there and people start using it, we won't be able to get rid of it later. Lets make sure this is needed before doing it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. <button> is the biggest issue we had, since it gets both click and keypress. <a> should not be used with ng-click (that's what buttons are for) but rather ng-href and routing...although I suppose that could be abused. There's also the <details>/<summary> elements, <dialog>, form controls, and a few more. An interesting thing to consider, as well, is the work being done on Custom Elements and tabindex: https://docs.google.com/document/d/1k93Ez6yNSyWQDtGjdJJqTBPmljk9l2WS3JTe5OHHB50/edit#heading=h.tf9twftfr65h

So, we need some mechanism of checking whether or not to apply keypress–I'm personally in favor of opt-in for <div> and <li> so that it limits the scope of this behavior. It's just a question of whether we want that list to be configurable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configurable is good, but I think we shouldn't expose an array for it at least.

If we decide we don't want it to be configurable and just "do the right thing always" later, it's trivial to replace configuration methods with noop, and not have anything unnecessary taking up space in the framework. So I see that as being preferable, tbh

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like

// enable keypress on all elements!
$ariaProvider.keypressClickElements('*');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would that allow all elements by default? How would we discern between <div> and <button> (and fix the issue this is trying to address) out of the box?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caitp revisiting this so we can get a fix in to the next release. I'm still unclear how we would fix the bug with a wildcard for all elements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wildcard case would just not filter, or only blacklist known-issue elements, I guess.

Maybe it's not worth worrying about it and just land it, @lgalfaso what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we just do away with the config for elements and limit dynamic binding of keypress to div and li? We could wait and see if anyone actually needs it to be configurable. You'd still be able to disable it with the bindKeypress flag.

@marcysutton
Copy link
Contributor Author

@caitp I simplified the code to just Do the Right Thing™ without a configuration array. I also updated the docs.

@caitp
Copy link
Contributor

caitp commented Feb 6, 2015

okay, i think a blacklist would be better than a whitelist, but this is fine for now... @petebacondarwin / @Narretz / @lgalfaso could you merge this before monday?

@petebacondarwin
Copy link
Member

Will do

@marcysutton
Copy link
Contributor Author

Thanks @petebacondarwin!

@marcysutton marcysutton deleted the ngaria-ngclick-bugfix branch April 11, 2015 21:15
@AshutoshAm
Copy link

try this .. its 100% works for me ...

.config(function( $mdGestureProvider ) {
$mdGestureProvider.skipClickHijack();
})

source..
https://rubberchickin.com/issue-with-ng-click-on-ios-firing-twice/

@marcysutton
Copy link
Contributor Author

@Ashutosh7376 that is unrelated to this change, and only applicable to Angular Material.

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

Successfully merging this pull request may close these issues.

bug(ngAria): ng-click adds keypress event to buttons which already fire a click event on "enter"
6 participants