Skip to content

Commit

Permalink
Merge pull request #907 from nhsuk/feature/button-js-fix
Browse files Browse the repository at this point in the history
Fixed bug where buttons added after page load don't activate JS behaviours
  • Loading branch information
andymantell authored Dec 7, 2023
2 parents ef40d37 + e1f7b70 commit 5692eed
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 34 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
- Updated header component unit tests ([PR 900](https://github.com/nhsuk/nhsuk-frontend/pull/900)).
- Fixed bug where the header didn't align with the main width container ([PR 902](https://github.com/nhsuk/nhsuk-frontend/pull/902)). This fixes [Issue 901](https://github.com/nhsuk/nhsuk-frontend/issues/901)

:new: **New features**

- Add and export new `initAll` method in `nhsuk.js`, and pass document by default, but allowing smaller DOM scopes to be passed. This allows new nhsuk-frontend JS components to be initialised after page load, such as in new pieces of DOM added by JavaScript.
- This fixes [issue 906](https://github.com/nhsuk/nhsuk-frontend/issues/906) where button elements added _after_ the page has loaded would not benefit from the button component's JS behaviours (double click prevention and space bar activation for links). ([PR 907](https://github.com/nhsuk/nhsuk-frontend/pull/907)).

## 8.0.2 - 19 October 2023

:wrench: **Fixes**
Expand Down
4 changes: 2 additions & 2 deletions packages/components/button/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ class Button {
}
}

export default () => {
const buttons = document.querySelectorAll('[data-module="nhsuk-button"]')
export default ({ scope = document } = {}) => {
const buttons = scope.querySelectorAll('[data-module="nhsuk-button"]')
buttons.forEach((el) => {
new Button(el).init()
})
Expand Down
4 changes: 2 additions & 2 deletions packages/components/character-count/character-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ CharacterCount.prototype.defaults = {
wordCountAttribute: 'data-maxwords'
}

export default () => {
const characterCounts = document.querySelectorAll('[data-module="nhsuk-character-count"]')
export default ({ scope = document } = {}) => {
const characterCounts = scope.querySelectorAll('[data-module="nhsuk-character-count"]')
characterCounts.forEach((el) => {
new CharacterCount(el).init()
})
Expand Down
4 changes: 2 additions & 2 deletions packages/components/checkboxes/checkboxes.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ const unCheckExclusiveInputs = function unCheckExclusiveInputs(input) {
syncAllConditionalReveals(input)
}

export default () => {
export default ({ scope = document } = {}) => {
// Checkbox input DOMElements inside a conditional form group
const checkboxInputs = document.querySelectorAll('.nhsuk-checkboxes .nhsuk-checkboxes__input')
const checkboxInputs = scope.querySelectorAll('.nhsuk-checkboxes .nhsuk-checkboxes__input')

/**
* Toggle classes and attributes
Expand Down
8 changes: 4 additions & 4 deletions packages/components/details/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { toggleAttribute } from '../../common'
* Test at http://0.0.0.0:3000/components/details/index.html
*/

export default () => {
export default ({ scope = document } = {}) => {
// Does the browser support details component
const nativeSupport = typeof document.createElement('details').open === 'boolean'
if (nativeSupport) {
return
}

// Nodelist of all details elements
const allDetails = document.querySelectorAll('details')
const allDetails = scope.querySelectorAll('details')

/**
* Adds all necessary functionality to a details element
Expand All @@ -28,11 +28,11 @@ export default () => {
if (!element.id) element.setAttribute('id', `nhsuk-details${index}`)

// Set content element and give it an ID if it doesn't already have one
const content = document.querySelector(`#${element.id} .nhsuk-details__text`)
const content = scope.querySelector(`#${element.id} .nhsuk-details__text`)
if (!content.id) content.setAttribute('id', `nhsuk-details__text${index}`)

// Set summary element
const summary = document.querySelector(`#${element.id} .nhsuk-details__summary`)
const summary = scope.querySelector(`#${element.id} .nhsuk-details__summary`)

// Set initial summary aria attributes
summary.setAttribute('role', 'button')
Expand Down
4 changes: 2 additions & 2 deletions packages/components/error-summary/error-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ function handleClick(event) {
}
}

export default ({ focusOnPageLoad = true } = {}) => {
export default ({ focusOnPageLoad = true, scope = document } = {}) => {
// Error summary component
const errorSummary = document.querySelector('.nhsuk-error-summary')
const errorSummary = scope.querySelector('.nhsuk-error-summary')

if (errorSummary) {
// Focus error summary component if it exists
Expand Down
4 changes: 2 additions & 2 deletions packages/components/radios/radios.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { toggleConditionalInput } from '../../common'
* Test at http://0.0.0.0:3000/components/radios/conditional.html
*/

export default () => {
export default ({ scope = document } = {}) => {
// Radio input HTMLElements inside a conditional form group
const radioInputs = document.querySelectorAll('.nhsuk-radios--conditional .nhsuk-radios__input')
const radioInputs = scope.querySelectorAll('.nhsuk-radios--conditional .nhsuk-radios__input')

/**
* Update all conditional reveals to match checked state
Expand Down
4 changes: 2 additions & 2 deletions packages/components/tabs/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ class Tabs {
* Tabs({responsive: false});
* Tabs({namespace: 'my-custom-namespace'}); // Alters classes allowing alternative css
*/
export default ({ namespace = 'nhsuk-tabs', responsive = true, historyEnabled = true } = {}) => {
const tabs = document.querySelectorAll(`[data-module="${namespace}"]`)
export default ({ namespace = 'nhsuk-tabs', responsive = true, historyEnabled = true, scope = document } = {}) => {
const tabs = scope.querySelectorAll(`[data-module="${namespace}"]`)
tabs.forEach((el) => {
new Tabs(el, namespace, responsive, historyEnabled).init()
})
Expand Down
49 changes: 31 additions & 18 deletions packages/nhsuk.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
// Components
import Button from './components/button/button'
import CharacterCount from './components/character-count/character-count'
import Checkboxes from './components/checkboxes/checkboxes'
import Details from './components/details/details'
import ErrorSummary from './components/error-summary/error-summary'
import Header from './components/header/header'
import Radios from './components/radios/radios'
import SkipLink from './components/skip-link/skip-link'
import Tabs from './components/tabs/tabs'
import initButton from './components/button/button'
import initCharacterCount from './components/character-count/character-count'
import initCheckboxes from './components/checkboxes/checkboxes'
import initDetails from './components/details/details'
import initErrorSummary from './components/error-summary/error-summary'
import initHeader from './components/header/header'
import initRadios from './components/radios/radios'
import initSkipLink from './components/skip-link/skip-link'
import initTabs from './components/tabs/tabs'

import './polyfills'

/**
* Use this function to initialise nhsuk-frontend components within a
* given scope. This function is called by default with the document
* element, but you can call it again later with a new DOM element
* containing nhsuk-frontend components which you wish to initialise.
*
* @param {HTMLElement} scope
*/
export function initAll(scope) {
initButton({ scope })
initCharacterCount({ scope })
initCheckboxes({ scope })
initDetails({ scope })
initErrorSummary({ scope })
initRadios({ scope })
initTabs({ scope })
}

// Initialize components
document.addEventListener('DOMContentLoaded', () => {
CharacterCount()
Button()
Checkboxes()
Details()
ErrorSummary()
Header()
Radios()
SkipLink()
Tabs()
initHeader()
initSkipLink()

initAll(document)
})

0 comments on commit 5692eed

Please sign in to comment.