-
Notifications
You must be signed in to change notification settings - Fork 327
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
Users can now conditionally reveal content on pages with multiple grouped radios #1497
Conversation
nodeListForEach($allInputs, function ($input) { | ||
this.setAttributes($input) | ||
// In radios, only radios with the same name will affect each other. |
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 we have a test for this? 🤔
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 all this will do is sync the conditional reveals with the checked state of their inputs, we'd have to do something really weird, like having another set of radios with a conditional reveal that's 'out of sync' with its radios, and asserting that it doesn't sync them back up again.
It's such a synthetic scenario I'm not sure it makes much sense as a test.
dae265e
to
037c1f6
Compare
@@ -40,18 +39,27 @@ Radios.prototype.setAttributes = function ($input) { | |||
var inputIsChecked = $input.checked | |||
$input.setAttribute('aria-expanded', inputIsChecked) | |||
|
|||
var $content = this.$module.querySelector('#' + $input.getAttribute('aria-controls')) | |||
var $content = document.querySelector('#' + $input.getAttribute('aria-controls')) |
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.
Just realised I've confused myself.
This line is the one that's important that it isnt global, not the others.
Going to have to figure this out...
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, we can't assume that 'aria-controls' on a radio means that the user has only conditional reveals.
In this case that we fixed, they put their own aria-controls on the radio for something unrelated.
I think we'll need to do something at the initialisation stage to avoid this...
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.
We either need to have a way of querying the $module
in which the given $input
exists, or query the whole document
, as this.$module
will only search within the scope of the module of the clicked radio.
In terms of checking for aria-controls on something unrelated, yesterday you suggested checking for govuk-radios__conditional
in $content.classList
, which sounds like a sane defence?
If we do that, then scoping this to the document seems OK to me as we'll always just be syncing the --hidden
class with the checked state of the input?
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.
Yeah I forgot about the idea of looking for that class, that'll be the ticket thanks Ollie.
// | ||
// We also only want radios which have aria-controls, as they support conditional reveals. | ||
var $scope = ($clickedInput.form || document) | ||
var $allInputs = $scope.querySelectorAll('input[type="radio"][aria-controls]') |
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.
This is probably something of an edge-case but this won't query any inputs that are outside of the form but associated with it using form="form-id"
as they won't be children of the form.
I'd suggest instead checking the form attribute of both within the forEach, i.e. if ($input.form === $clicked.form)
65e843f
to
42ab630
Compare
Blocking this on the release notes being merged, so I can add a CHANGELOG entry... |
42ab630
to
6eb6c86
Compare
6eb6c86
to
e7f5257
Compare
e7f5257
to
eded390
Compare
I wasn't up to date with my branch on my work computer and force pushed over some of my changes, so I'll sort this out when I get home... |
eded390
to
42ab630
Compare
When multiple groups of radios with the same `name` appear on a page, selecting any radio button may cause radio buttons in other groups to become deselected. However, because we only previously triggered setAttributes on radio buttons within the same $module, the conditional reveals associated with the now-unchecked radios would still be visible. By triggering setAttributes on all radios in the document, we can avoid this. This should be safe as all we're doing is syncing the visibility of the conditional reveal with its associated input.
This stops this loop for running unnecessarily, for example for clicks in an open conditional reveal.
We did not need the radios check as the querySelector already had `[type="radio"]`. We can also remove the aria-controls check by movin it into the querySelector as `[aria-controls]`.
We do not need to run this code for other inputs as their state will not have changed.
By doing this alongside checking the name we only run setAttributes on the radio inputs that could change.
Since sometimes users set aria-controls unrelated to conditional reveals we need to be extra careful here. See #1156 for more context.
42ab630
to
8665fa5
Compare
@36degrees suggested that I use the GitHub info log in this pull request to target the commit before I forced pushed which worked fine... |
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.
LGTM 👍
@@ -37,21 +36,35 @@ Radios.prototype.init = function () { | |||
} | |||
|
|||
Radios.prototype.setAttributes = function ($input) { | |||
var inputIsChecked = $input.checked | |||
$input.setAttribute('aria-expanded', inputIsChecked) | |||
var $content = document.querySelector('#' + $input.getAttribute('aria-controls')) |
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.
Non-blocking: It could be worth leaving a comment here to say that we use document
as the scope to cater for the edge case when other radios with conditionals are part of the same group. It might not be immediately clear that there could be other radios that are in fact related even though they're outside $module
.
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 originally put a comment in but @36degrees thought that if we were doing this from scratch that we probably wouldnt have commented it. The case you're talking about is described in the test suite, so maybe that's enough? What do you think?
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 if someone changed this the tests would fail so I'm going to go with what Ollie and I discussed originally so can get this merged 🐎
@NickColley #1079 is about being able to group related radios together - is that made possible from this PR? |
@edwardhorsford this allows you to do the conditional reveals when you have groups of radios with the same name, so I think so! :) This'll go out very soon in 3.0.0. If you need a different use case feel free to open an new issue for us to consider. |
This pull request is a continuation of the work that @colinrotherham and @frankieroberto have proposed: #1297
It is similar to Frankie's original suggestion but keeps the scope as small as possible to avoid running JavaScript unnecessarily.
Fixes #1079
Closes #1297