Jump to content

List box data type multi-select to single-select validation


Recommended Posts

Hello,

I was wondering if anyone knows how to achieve the following or has a script written that handles list box options validation.

First, I don't want to modify the data type to text as a workaround. I understand that the list box data type has several limitations but need to keep it as a list box data type for the project I am working on.

I see in the article below that you can set a limit for the maximum checkbox options on a list box field.

https://howto.caspio.com/tech-tips-and-articles/setting-the-maximum-number-of-listbox-selections-in-forms/

Does anyone know how to modify this script or write one that achieves the following:

I want to uncheck all other checked list box items when a certain list box option is checked. In other words,  when a certain value is checked I want the list box to operate as a single selection and not as a multi-selection.

For example I have the following field:

Race:

  • African American or Black
  • American Indian or Alaskan Native
  • Asian
  • Native Hawaiian or Pacific Islander
  • White
  • Prefer to self-describe
  • Prefer not to answer

When user checks the last option "Prefer not to answer" I want to uncheck all other options (if already checked) and grey them out, similar to how the max number script above functions. I am looking for a solution that works on both Submission form and Detail update datapages.

Per requirements, the user can select more than one race but when selecting Prefer not to answer that should be the only value selected. I want to enforce that rule through a script (instead of relying on user accuracy).

 

Link to comment
Share on other sites

Hi @ChrisCarlson

You can try the following code on the submission form:
 

<script>
if (document.addEventListeners == undefined) {
  
const targetFieldName = 'Race'
const targetOptionName = 'Prefer not to answer'

const targetCheckbox = {HTMLCheckbox: '', correspondingValue: ''}

const setTragetCheckBox = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="InsertRecord${targetFieldName}"]`).forEach(input=>{
if(input.nextElementSibling.innerHTML.trim()!=targetOptionName) {return}
  targetCheckbox.HTMLCheckbox = input

})
}

const addObserver = () => {
let observer = new MutationObserver((mutations)=>{

for (let i=0; i<mutations.length; i++) {
if (mutations[i].addedNodes == null) {continue}
if (mutations[i].addedNodes.length==0) {continue}
if (mutations[i].addedNodes[0].getAttribute == undefined) {continue}
if (mutations[i].addedNodes[0].getAttribute('class') == undefined) {continue}
if (mutations[i].addedNodes[0].getAttribute('class').indexOf('cbFormMultiSelectText') == -1) {continue}
if (mutations[i].addedNodes[0].parentElement.parentElement.parentElement.parentElement.parentElement.id.indexOf(`${targetFieldName}`) == -1) {continue}
setTragetCheckBox()
observer.disconnect()
}
})
observer.observe(document.querySelector('body'), {childList: true, subtree: true})
}

const enableCheckBoxes = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="InsertRecord${targetFieldName}"]`).forEach(input=>{
if(input==targetCheckbox.HTMLCheckbox) {return}
  input.removeAttribute('disabled')
})
}

const disableCheckBoxes = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="InsertRecord${targetFieldName}"]`).forEach(input=>{
if(input==targetCheckbox.HTMLCheckbox) {return}

 if(input.checked) {
input.checked = false
}
input.setAttribute('disabled', 'disabled')
})
}

const addListener = (input) => {
input.addEventListener('change', e=>{

if (targetCheckbox.HTMLCheckbox.checked) {

 if (targetCheckbox.correspondingValue == '') {
 let tempArr = e.target.value.split(',')

 targetCheckbox.correspondingValue = tempArr[tempArr.length-1]
 }

e.target.value = targetCheckbox.correspondingValue

disableCheckBoxes()
}
else {
enableCheckBoxes ()
}
})
}

const addEventListeners = (e) => {
if (e.detail.appKey != '[@cbAppKey]') {return}
let input = document.querySelector(`[name^="InsertRecord${targetFieldName}"]`)
addListener(input)
addObserver()
}


document.addEventListener('DataPageReady', addEventListeners )
document.addEventListeners = 'enabled'
}
</script>

Live example: https://c7eku786.caspio.com/dp/7f80b000f0a352c20164478fbeb6


And this code on Details DataPage:
 

<!-- Details DP  -->

<script>
if (document.addEventListeners == undefined) {
  
const targetFieldName = 'Race'
const targetOptionName = 'Prefer not to answer'

const targetCheckbox = {HTMLCheckbox: '', correspondingValue: ''}

const setTragetCheckBox = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="EditRecord${targetFieldName}"]`).forEach(input=>{
if(input.nextElementSibling.innerHTML.trim()!=targetOptionName) {return}
  targetCheckbox.HTMLCheckbox = input
  if (input.checked) {
  disableCheckBoxes()
  }
})
}

const addObserver = () => {
let observer = new MutationObserver((mutations)=>{

for (let i=0; i<mutations.length; i++) {
if (mutations[i].addedNodes == null) {continue}
if (mutations[i].addedNodes.length==0) {continue}
if (mutations[i].addedNodes[0].getAttribute == undefined) {continue}
if (mutations[i].addedNodes[0].getAttribute('class') == undefined) {continue}
if (mutations[i].addedNodes[0].getAttribute('class').indexOf('cbFormMultiSelectText') == -1) {continue}
if (mutations[i].addedNodes[0].parentElement.parentElement.parentElement.parentElement.parentElement.id.indexOf(`${targetFieldName}`) == -1) {continue}
setTragetCheckBox()
//observer.disconnect()
}
})
observer.observe(document.querySelector('body'), {childList: true, subtree: true})
}

const enableCheckBoxes = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="EditRecord${targetFieldName}"]`).forEach(input=>{
if(input==targetCheckbox.HTMLCheckbox) {return}
  input.removeAttribute('disabled')
})
}

const disableCheckBoxes = () => {

document.querySelectorAll(`.cbFormMultiSelectText input[id*="EditRecord${targetFieldName}"]`).forEach(input=>{

if(input==targetCheckbox.HTMLCheckbox) {return}

 if(input.checked) {
input.checked = false
}
input.setAttribute('disabled', 'disabled')
})
}

const addListener = (input) => {
input.addEventListener('change', e=>{

if (targetCheckbox.HTMLCheckbox.checked) {

 if (targetCheckbox.correspondingValue == '') {
 let tempArr = e.target.value.split(',')

 targetCheckbox.correspondingValue = tempArr[tempArr.length-1]
 }

e.target.value = targetCheckbox.correspondingValue

disableCheckBoxes()
}
else {
enableCheckBoxes ()
}
})
}

const addEventListeners = (e) => {
if (e.detail.appKey != '[@cbAppKey]') {return}
let input = document.querySelector(`[name^="EditRecord${targetFieldName}"]`)
addListener(input)
addObserver()
}


document.addEventListener('DataPageReady', addEventListeners )
document.addEventListeners = 'enabled'
}
</script>


Live example: https://c7eku786.caspio.com/dp/7f80b000d3cf364313bc4e50a19b

You would need to change respective variable values to match the name of your List string field and option that should disable all options:

  
const targetFieldName = 'Race'
const targetOptionName = 'Prefer not to answer'

 

Link to comment
Share on other sites

Volomeister,

Thanks some much for posting the script! It works great except does not seem to work if I want to set it up on more than one field on the same datapage, when repeating the same script for each additional field. For example, I have a field called race with the option (as described above) and an additional field for gender with the same option. I pasted the script twice into my footer of submission datapage. It works good for the first instance of field on the datapage, but the second field (and I am presuming any additional fields) does not respond. This was tested in a submission form.

Link to comment
Share on other sites

Hi @ChrisCarlson

To make it work for each consecutive field, just slightly modify the "addEventListeners" in every place in the code. For example, change it to "addEventListeners1" 
I.e., if I want to make it work for XXX field for option "Choice 3" as well, the code will look like this:
 

<!-- Submission form DP  -->

<script>
if (document.addEventListeners1 == undefined) {
  
const targetFieldName = 'XXX'
const targetOptionName = 'Choice 3'

const targetCheckbox = {HTMLCheckbox: '', correspondingValue: ''}

const setTragetCheckBox = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="InsertRecord${targetFieldName}"]`).forEach(input=>{
if(input.nextElementSibling.innerHTML.trim()!=targetOptionName) {return}
  targetCheckbox.HTMLCheckbox = input

})
}

const addObserver = () => {
let observer = new MutationObserver((mutations)=>{

for (let i=0; i<mutations.length; i++) {
if (mutations[i].addedNodes == null) {continue}
if (mutations[i].addedNodes.length==0) {continue}
if (mutations[i].addedNodes[0].getAttribute == undefined) {continue}
if (mutations[i].addedNodes[0].getAttribute('class') == undefined) {continue}
if (mutations[i].addedNodes[0].getAttribute('class').indexOf('cbFormMultiSelectText') == -1) {continue}
if (mutations[i].addedNodes[0].parentElement.parentElement.parentElement.parentElement.parentElement.id.indexOf(`${targetFieldName}`) == -1) {continue}
setTragetCheckBox()
observer.disconnect()
}
})
observer.observe(document.querySelector('body'), {childList: true, subtree: true})
}

const enableCheckBoxes = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="InsertRecord${targetFieldName}"]`).forEach(input=>{
if(input==targetCheckbox.HTMLCheckbox) {return}
  input.removeAttribute('disabled')
})
}

const disableCheckBoxes = () => {
document.querySelectorAll(`.cbFormMultiSelectText input[id*="InsertRecord${targetFieldName}"]`).forEach(input=>{
if(input==targetCheckbox.HTMLCheckbox) {return}

 if(input.checked) {
input.checked = false
}
input.setAttribute('disabled', 'disabled')
})
}

const addListener = (input) => {
input.addEventListener('change', e=>{

if (targetCheckbox.HTMLCheckbox.checked) {

 if (targetCheckbox.correspondingValue == '') {
 let tempArr = e.target.value.split(',')

 targetCheckbox.correspondingValue = tempArr[tempArr.length-1]
 }

e.target.value = targetCheckbox.correspondingValue

disableCheckBoxes()
}
else {
enableCheckBoxes ()
}
})
}

const addEventListeners1 = (e) => {
if (e.detail.appKey != '[@cbAppKey]') {return}
let input = document.querySelector(`[name^="InsertRecord${targetFieldName}"]`)
addListener(input)
addObserver()
}


document.addEventListener('DataPageReady', addEventListeners1 )
document.addEventListeners1 = 'enabled'
}
</script>

 

Link to comment
Share on other sites

Volomeister,

Thanks for the updated script. Your suggestion worked well for the more than 1 field approach.

A couple issues I am running into:

1. When submitting the submission form and receiving a page error (for example, some other required field not filled out), if the user selects any option other than "Prefer not to answer" (the targetOptionName value) before submission, when the page displays after submission in the error state, it allows for any options to be selected and the script uncheck/greyout controls stops working. This only seems to be an issue on the submission datapage script, as the details page script works correctly on page errors. And this only is an issue if they select a non-targetOptionName value (if they selected the targetOptionName value before submit, the script still functions correctly when page error occurs).

2. Is it possible to make the checkbox greyout reverse in logic. For example, I have 5 multiselect options. One of them is "Prefer not to answer" which is the targetOptionName and handles great with this script, but I have another field with "Prefer to self-describe" which displays another text field for "Self-Described Race" using Caspio's built-in conditional logic where it hides/displays via a form section. The built in conditional logic does not trigger the form section hide when this script unchecks and greys out the affected option. The built in conditional logic seems to require end user click to trigger. Even though the addition of the 2nd function below would cause the user to have to manually uncheck values to be able to check the targetOptionName checkbox, it would solve the issue with the conditional logic failing to trigger by forcing the end user to click/unclick the checkbox that has conditional logic and trigger it.

Are you able to edit the script to include #2 below?

  1. When targetOptionName is checked, uncheck and grey out all other checkboxes (this is working great with this script)
  2. When any other checkbox other than targetOptionName is checked, grey out targetOptionName checkbox. User has to uncheck the checkboxes to get targetOptionName to un-greyout.

Thanks again for all your help!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...