app/javascript/blacklight/checkbox_submit.js
/* Converts a "toggle" form, with single submit button to add/remove
something, like used for Bookmarks, into an AJAXy checkbox instead.
Apply to a form. Does require certain assumption about the form:
1) The same form 'action' href must be used for both ADD and REMOVE
actions, with the different being the hidden input name="_method"
being set to "put" or "delete" -- that's the Rails method to pretend
to be doing a certain HTTP verb. So same URL, PUT to add, DELETE
to remove. This plugin assumes that.
Plus, the form this is applied to should provide a data-doc-id
attribute (HTML5-style doc-*) that contains the id/primary key
of the object in question -- used by plugin for a unique value for
DOM id's.
Uses HTML for a checkbox compatible with Bootstrap 4.
new CheckboxSubmit(document.querySelector('form.something')).render()
*/
export default class CheckboxSubmit {
constructor(form) {
this.form = form
}
async clicked(evt) {
this.spanTarget.innerHTML = this.form.getAttribute('data-inprogress')
this.labelTarget.setAttribute('disabled', 'disabled');
this.checkboxTarget.setAttribute('disabled', 'disabled');
const response = await fetch(this.formTarget.getAttribute('action'), {
body: new FormData(this.formTarget),
method: this.formTarget.getAttribute('method').toUpperCase(),
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': document.querySelector('meta[name=csrf-token]')?.content
}
})
this.labelTarget.removeAttribute('disabled')
this.checkboxTarget.removeAttribute('disabled')
if (response.ok) {
const json = await response.json()
this.updateStateFor(!this.checked)
document.querySelector('[data-role=bookmark-counter]').innerHTML = json.bookmarks.count
} else {
alert('Error')
}
}
get checked() {
return (this.form.querySelectorAll('input[name=_method][value=delete]').length != 0)
}
get formTarget() {
return this.form
}
get labelTarget() {
return this.form.querySelector('[data-checkboxsubmit-target="label"]')
}
get checkboxTarget() {
return this.form.querySelector('[data-checkboxsubmit-target="checkbox"]')
}
get spanTarget() {
return this.form.querySelector('[data-checkboxsubmit-target="span"]')
}
updateStateFor(state) {
this.checkboxTarget.checked = state
if (state) {
this.labelTarget.classList.add('checked')
//Set the Rails hidden field that fakes an HTTP verb
//properly for current state action.
this.formTarget.querySelector('input[name=_method]').value = 'delete'
this.spanTarget.innerHTML = this.form.getAttribute('data-present')
} else {
this.labelTarget.classList.remove('checked')
this.formTarget.querySelector('input[name=_method]').value = 'put'
this.spanTarget.innerHTML = this.form.getAttribute('data-absent')
}
}
}