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

Users can now conditionally reveal content on pages with multiple grouped radios #1497

Merged
merged 8 commits into from
Jul 23, 2019

Conversation

NickColley
Copy link
Contributor

@NickColley NickColley commented Jul 16, 2019

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

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 16, 2019 11:11 Inactive
nodeListForEach($allInputs, function ($input) {
this.setAttributes($input)
// In radios, only radios with the same name will affect each other.
Copy link
Contributor Author

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? 🤔

Copy link
Contributor

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.

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 16, 2019 11:18 Inactive
@@ -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'))
Copy link
Contributor Author

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.

#1156

Going to have to figure this out...

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 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...

Copy link
Contributor

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?

Copy link
Contributor Author

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]')
Copy link
Contributor

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)

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 16, 2019 13:23 Inactive
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 16, 2019 13:40 Inactive
@NickColley NickColley marked this pull request as ready for review July 16, 2019 13:42
@NickColley
Copy link
Contributor Author

Blocking this on the release notes being merged, so I can add a CHANGELOG entry...

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 17, 2019 14:08 Inactive
@NickColley NickColley added this to the v3.0.0 milestone Jul 17, 2019
@NickColley NickColley changed the title Trigger setAttributes on radio inputs with shared form owner Support multiple grouped radios with conditional reveals Jul 17, 2019
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 17, 2019 14:13 Inactive
@NickColley NickColley changed the title Support multiple grouped radios with conditional reveals Users can now conditionally reveal content on pages with multiple grouped radios Jul 17, 2019
@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 17, 2019 14:16 Inactive
@NickColley
Copy link
Contributor Author

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...

@govuk-design-system-ci govuk-design-system-ci temporarily deployed to govuk-frontend-review-pr-1497 July 17, 2019 14:30 Inactive
NickColley and others added 3 commits July 17, 2019 15:31
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.
NickColley and others added 5 commits July 17, 2019 15:31
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.
@NickColley
Copy link
Contributor Author

@36degrees suggested that I use the GitHub info log in this pull request to target the commit before I forced pushed which worked fine...

Copy link
Member

@hannalaakso hannalaakso left a 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'))
Copy link
Member

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.

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 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?

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 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 NickColley merged commit 0bce5fc into master Jul 23, 2019
@NickColley NickColley deleted the radio-trigger-setattributes branch July 23, 2019 09:33
@edwardhorsford
Copy link
Contributor

@NickColley #1079 is about being able to group related radios together - is that made possible from this PR?

@NickColley
Copy link
Contributor Author

@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.

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

Successfully merging this pull request may close these issues.

Ability to group radio buttons / checkboxes within sub-headings
5 participants