Skip to content

Instantly share code, notes, and snippets.

@renoirb
Last active June 10, 2021 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renoirb/42e5bc19bcaf08eb8e3e7cc42adf051f to your computer and use it in GitHub Desktop.
Save renoirb/42e5bc19bcaf08eb8e3e7cc42adf051f to your computer and use it in GitHub Desktop.
Input and button clicking event without framework

Input type checkbox activated by button

This is common pattern, a "prettier" button showing a checkbox when checked

<!DOCTYPE html>
<html>
<body>
Checkbox: <input type="checkbox" id="myCheck">
Checkbox2: <input type="checkbox" id="myCheck2">
<button onclick="check('#myCheck', this)">Check Checkbox</button>
<script>
function check(cssSelector, button) {
const elements = document.querySelectorAll(cssSelector)
if (elements.length > 1) {
const message = `There are more than ${elements.length} elements matching ${cssSelector}`
throw new Error(message)
} else {
if (elements[0].getAttribute('type') !== 'checkbox' || elements[0].localName !== 'input') {
const message = `This should only work when the refered element is an input of type checkbox!, element as ${cssSelector} isn’t one`
throw new Error(message)
}
const checkHandler = (event) => {
const hasChecked = elements[0].hasAttribute('checked')
if (hasChecked) {
elements[0].removeAttribute('checked')
} else {
elements[0].setAttribute('checked', '')
}
console.log('check on button', { button, event, hasChecked })
}
if (('isBound' in button.dataset) === false) {
button.dataset.isBound = true
button.addEventListener("click", checkHandler);
button.dispatchEvent(new MouseEvent('click'))
console.log('check not isBound', { button })
} else {
console.log('check isBound', { button })
}
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<div>
<div>
<h2>Check box</h2>
Checkbox: <input type="checkbox" id="myCheck" />
<button
data-for="checkbox"
data-for-on="#myCheck"
style="width: 100px; height: 100px"
></button>
</div>
<div id="alive">
<h2>Check box 2</h2>
Checkbox: <input type="checkbox" checked="0" /><!-- no id! -->
<button
data-for="checkbox"
data-for-on="#alive input"
style="width: 100px; height: 100px"
><!-- as long as data-for-on has a valid CSS selector --></button>
</div>
</div>
<template data-for-icon="checkbox">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
viewBox="0 0 20 20"
>
<filter id="checked">
<feGaussianBlur stdDeviation="1" />
</filter>
<path
fill-rule="evenodd"
d="M2.166 4.999A11.954 11.954 0 0010 1.944 11.954 11.954 0 0017.834 5c.11.65.166 1.32.166 2.001 0 5.225-3.34 9.67-8 11.317C5.34 16.67 2 12.225 2 7c0-.682.057-1.35.166-2.001zm11.541 3.708a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd"
/>
</svg>
</template>
<script>
const mutateButtonInnerSvgUsingFilter = (hiddenInput, svgParent) => {
const isChecked = hiddenInput.hasAttribute('checked')
const maybeChildSvg = svgParent.firstElementChild
if (maybeChildSvg && maybeChildSvg.localName === 'svg') {
const svgChild = maybeChildSvg.querySelector('path') // Would not work with g TODO!
if (isChecked) {
svgChild.setAttribute('filter', 'url(#checked)')
} else {
svgChild.removeAttribute('filter')
}
}
}
function forCheckbox(button) {
if (button) {
const { dataset = {} } = button
const { for: forElement, forOn = false } = dataset
let targetHiddenInput
if (forOn && forElement) {
const subjects = Array.from(document.querySelectorAll(forOn))
if (subjects.length !== 1) {
const message = `There are more than ${subject.length} elements matching ${forOn}`
throw new Error(message)
}
targetHiddenInput = subjects[0]
if (
targetHiddenInput.getAttribute('type') !== 'checkbox' ||
targetHiddenInput.localName !== 'input'
) {
message = `This should only work when the refered element is an input of type checkbox!, element as ${forOn} isn’t one`
throw new Error(message)
}
} else {
const message = `Missing expected dataset items data-for-on, and data-for attributes`
throw new Error(message)
}
const checkHandler = (event) => {
const isChecked = targetHiddenInput.hasAttribute('checked')
if (isChecked) {
event.target.classList.remove('with-svg-icon-checked')
targetHiddenInput.removeAttribute('checked')
} else {
event.target.classList.add('with-svg-icon-checked')
targetHiddenInput.setAttribute('checked', '')
}
mutateButtonInnerSvgUsingFilter(targetHiddenInput, event.target)
}
button.addEventListener('click', checkHandler)
button.dataset.forOnBound = true
mutateButtonInnerSvgUsingFilter(targetHiddenInput, button)
} else {
const message = `Unexpected condition`
throw new TypeError(message)
}
}
;(() => {
const elements = document.querySelectorAll('[data-for]')
if (elements) {
const wm = new WeakMap()
const maybeIcons = Array.from(
document.querySelectorAll('[data-for-icon]'),
)
const findIconTemplate = (name) =>
(maybeIcons ?? []).find((i) => i.dataset.forIcon === name)
for (const e of elements) {
const { dataset = {} } = e
const { for: forElement, forOn = false } = dataset
if (forElement && forOn) {
const iconTemplate = findIconTemplate(forElement)
if (wm.has(e) === false) {
const targets = Array.from(document.querySelectorAll(forOn))
if (targets.length !== 1) {
const message = `There are more than ${targets.length} elements matching ${forOn}`
throw new Error(message)
}
const targetHiddenInput = targets[0]
if (iconTemplate) {
const { content } = iconTemplate
if (content && 'cloneNode' in content) {
e.classList.add('with-svg-icon')
e.classList.add(`with-svg-icon-${forElement}`)
var cloned = content.cloneNode(true)
e.appendChild(cloned)
}
}
switch (forElement) {
case 'checkbox':
forCheckbox(e)
break
default:
const message = `There are more than ${targets.length} elements matching ${forOn}`
throw new Error(message)
break
}
wm.set(e, forOn)
}
}
}
}
})()
</script>
<style>
button.with-svg-icon {
background-size: contain;
cursor: pointer;
border: none;
background: none;
}
button.with-svg-icon > * {
pointer-events: none;
}
</style>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment