Submit button of form doesn't work anymore after implementing CMS Select attribute

Hi Finsweet support,

In a previous post I was helped a lot with some issues I have encountered while using Finsweet CMS Select & Filter. I am very grateful about the help I have received. But after installing the new code I was provided with, I couldn’t use the submit button of my form anymore. I have tried searching for hidden elements within the form with “required” still checked and checking if the “listInstances” are still on the right place (as far as I can tell).

The read-only link: Webflow - Vidarte.nl 2.0

Best regards,
Micky

ps: The link to the previous post: Difficulties with implementing CMS Select & Filter

Hello @Vible! I believe the issue might originate from the CMS Filter setup. If you were trying to filter the Select collections you can remove the script and the element attributes as the code I provided on the other thread will manage the filtering.

Another thing that may be worth looking at is the errors on the console after a user tries to submit the form

Hi Luis,

Thank you for your reply! The form seems to be working. Unfortunately, I have encountered a minor issue.

I am using the Query Param attribute for the form. My issue is as follows: for example, when a user visits the page with pre-selected options and tries to change the starting date or the course, the options in the select fields are no longer available. It seems as if the Query Param attribute prevents the select and filter attributes from being triggered.

Do you happen to know what might be causing this issue?

Best regards,
Micky

Hey @Vible! Can you share a link with query params that replicate this issue, please?

Hi Luis,

Absolutely, this is a link with a starting date for a specific course: Schrijf je In voor een Opleiding bij Vidarte | Ontwikkeling Start Hier

Best regards,
Micky

Hey @Vible! We may need to write our own Query Param script… Would you be okay with changing the setup for this?

Hi Luis,

That is fine for me.

Hey @Vible!

Can you test this code?

<script>
  window.fsAttributes = window.fsAttributes || [];
  window.fsAttributes.push([
    'cmsselect',
    (listInstances) => {
      console.log('cmsselect successfully loaded!');

      const eventSelect = document.querySelector('[fs-cmsselect-element="select"]');
      const opleidingSelect = document.querySelector('[fs-cmsselect-element="select-2"]');
      const startdatumSelect = document.querySelector('[fs-cmsselect-element="select-3"]');

      const listInstance = listInstances[1];
      const startdatumListInstance = listInstances[2];

      const { items } = listInstance;
      const { items: startdatumItems } = startdatumListInstance;

      // Function to get query parameters from the URL
      function getQueryParams() {
        return Object.fromEntries(new URLSearchParams(window.location.search).entries());
      }

      // Function to populate form fields dynamically based on query parameters
      function populateFormFields() {
        const queryParams = getQueryParams();

        // Loop through each query parameter
        for (const [param, value] of Object.entries(queryParams)) {
          // Try to find a form field by 'name', 'id', or custom attribute
          const formField = document.querySelector(`[name="${param}"]`);

          if (formField) {
            if (formField.tagName === 'SELECT') {
              // For select elements, match the value with one of the options
              const optionToSelect = Array.from(formField.options).find(
                (option) => option.value === value || option.textContent.trim() === value
              );
              if (optionToSelect) {
                optionToSelect.selected = true;
              }
            } else {
              // For other input types
              formField.value = value;
            }
          }
        }
      }

      // Function to create a placeholder element for the select
      const createPlaceholder = (text) => {
        const placeholder = document.createElement('option');
        placeholder.value = '';
        placeholder.textContent = text;
        placeholder.selected = true;
        return placeholder;
      };

      // Populate fields when the page loads
      populateFormFields();

      // Event handling for the event select
      eventSelect.addEventListener('change', ({ target }) => {
        const selectValue = target.value;

        const filteredItems = items.filter(({ element }) => {
          if (!selectValue) return true;
          const textValue = element.querySelector('[fs-cmsselect-element]');
          return textValue?.getAttribute('data-category') === selectValue;
        });

        opleidingSelect.innerHTML = '';
        startdatumSelect.innerHTML = '';
        opleidingSelect.appendChild(createPlaceholder('Kies een optie...'));
        startdatumSelect.appendChild(createPlaceholder('Kies een optie...'));

        filteredItems.forEach(({ element }) => {
          const textValue = element.querySelector('[fs-cmsselect-element]');
          if (textValue) {
            const optionElement = document.createElement('option');
            optionElement.value = optionElement.textContent = textValue.textContent.trim();
            opleidingSelect.appendChild(optionElement);
          }
        });
      });

      // Event handling for the opleiding select
      opleidingSelect.addEventListener('change', ({ target }) => {
        const selectValue = target.value;

        const filteredItems = startdatumItems.filter(({ element }) => {
          if (!selectValue) return true;
          const textValue = element.querySelector('[fs-cmsselect-element]');
          return textValue?.getAttribute('data-category') === selectValue;
        });

        startdatumSelect.innerHTML = '';
        startdatumSelect.appendChild(createPlaceholder('Kies een optie...'));

        filteredItems.forEach(({ element }) => {
          const textValue = element.querySelector('[fs-cmsselect-element]');
          if (textValue) {
            const optionElement = document.createElement('option');
            optionElement.value = optionElement.textContent = textValue.textContent.trim();
            startdatumSelect.appendChild(optionElement);
          }
        });
      });
    },
  ]);
</script>

Note that the way of creating the query params has changed; we need to set the parameter name exactly as we have the name for the field, as this is case-sensitive.

Let me know how this works on your end!

Hi Luis,

I hope you’ve been doing well! It’s been a while, and I hope you had a great holiday season. I apologize for not responding earlier—I was on vacation.

Thank you for providing the new custom query parameter code! Unfortunately, the filter and select still don’t seem to trigger after clicking on a query parameter link. For example:

I might be overlooking something in the code or the query parameter link, but I can’t seem to figure it out. When you mentioned the “name” for the parameter, did you mean the class name or the name we assigned in the attribute?

Could you please help me out? I’ve added a new read-only link for you here:
https://preview.webflow.com/preview/vidarte-272759355fb7e4584-b5617dd191ad2?utm_medium=preview_link&utm_source=designer&utm_content=vidarte-272759355fb7e4584-b5617dd191ad2&preview=55e013cfd209e51a569fd2e3ac718a31&pageId=6719025c5b683e05b4300246&locale=nl&workflow=preview

Looking forward to hearing from you!

Best regards,
Micky

Hey @Vible! I hope you had a great holiday season too!

Regarding this

When you mentioned the “name” for the parameter, did you mean the class name or the name we assigned in the attribute?

I am referring to the native name attribute you can set on this field

After these names match, we can actually remove the Query Params Attribute.

I also wanted to ask if you could please record a quick Loom on the expected flow for the form. I may also be overlooking something or misunderstanding the functionality you are trying to achieve.

Thank you!

Hi Luis,

The adjustment was what we needed, it’s working now! There’s only one final adjustment needed for the form to work as intended. I’ve made a Loom recording to explain what the final adjustment needs to be. In short: I want the first and second choices to be locked after clicking on the query parameter URL. In the recording I explain why.

Here’s the link I used for the query parameter: https://www.vidarte.nl/opleidingen/inschrijven?Categorie=Systemisch%20werk&Opleiding=Familie-%20en%20Organisatieopstellingen&Startdatum=28-1-2025

I hope you can help me out with this final request. I’m looking forward to hear from you!

Best regards,
Micky

Sure! I’ve updated the script with some minor tweaks, ie. if a query param is missing the user should be able to still select that option by themselves.

Can you add this and let me know if I am missing anything?

<script>
  window.fsAttributes = window.fsAttributes || [];
  window.fsAttributes.push([
    'cmsselect',
    (listInstances) => {
      console.log('cmsselect successfully loaded!');

      const categorySelect = document.querySelector('[name="Categorie"]');
      const opleidingSelect = document.querySelector('[name="Opleiding"]');
      const startdatumSelect = document.querySelector('[name="Startdatum"]');

      const listInstance = listInstances[1];
      const startdatumListInstance = listInstances[2];

      const { items } = listInstance;
      const { items: startdatumItems } = startdatumListInstance;

      // Function to get query parameters from the URL
      function getQueryParams() {
        return Object.fromEntries(new URLSearchParams(window.location.search).entries());
      }

      // Function to create a placeholder element for the select
      const createPlaceholder = (text) => {
        const placeholder = document.createElement('option');
        placeholder.value = '';
        placeholder.textContent = text;
        placeholder.disabled = true;
        placeholder.selected = true;
        return placeholder;
      };

      // Function to apply cascading filters programmatically
      function applyCascadingFilters(queryParams) {
        let isCategoryFiltered = false;
        let isOpleidingFiltered = false;

        // Trigger 'Categorie' filtering
        if (queryParams.Categorie) {
          const categoryOption = Array.from(categorySelect.options).find(
            (option) => option.textContent.trim() === queryParams.Categorie
          );
          if (categoryOption) {
            categoryOption.selected = true;

            // Filter 'Opleiding'
            const filteredItems = items.filter(({ element }) => {
              const textValue = element.querySelector('[fs-cmsselect-element]');
              return textValue?.getAttribute('data-category') === queryParams.Categorie;
            });

            opleidingSelect.innerHTML = '';
            startdatumSelect.innerHTML = ''; // Reset 'Startdatum'
            opleidingSelect.appendChild(createPlaceholder('Kies een optie...'));
            startdatumSelect.appendChild(createPlaceholder('Kies een optie...'));

            filteredItems.forEach(({ element }) => {
              const textValue = element.querySelector('[fs-cmsselect-element]');
              if (textValue) {
                const optionElement = document.createElement('option');
                optionElement.value =
                  textValue.getAttribute('data-value') || textValue.textContent.trim();
                optionElement.textContent = textValue.textContent.trim();
                opleidingSelect.appendChild(optionElement);
              }
            });

            categorySelect.disabled = true; // Disable 'Categorie'
            isCategoryFiltered = true;
          }
        }

        // Trigger 'Opleiding' filtering
        if (queryParams.Opleiding && isCategoryFiltered) {
          const opleidingOption = Array.from(opleidingSelect.options).find(
            (option) => option.textContent.trim() === queryParams.Opleiding
          );
          if (opleidingOption) {
            opleidingOption.selected = true;

            // Filter 'Startdatum'
            const filteredItems = startdatumItems.filter(({ element }) => {
              const textValue = element.querySelector('[fs-cmsselect-element]');
              return textValue?.getAttribute('data-category') === queryParams.Opleiding;
            });

            startdatumSelect.innerHTML = '';
            startdatumSelect.appendChild(createPlaceholder('Kies een optie...'));

            filteredItems.forEach(({ element }) => {
              const textValue = element.querySelector('[fs-cmsselect-element]');
              if (textValue) {
                const optionElement = document.createElement('option');
                optionElement.value =
                  textValue.getAttribute('data-value') || textValue.textContent.trim();
                optionElement.textContent = textValue.textContent.trim();
                startdatumSelect.appendChild(optionElement);
              }
            });

            opleidingSelect.disabled = true; // Disable 'Opleiding'
            isOpleidingFiltered = true;
          }
        }

        // Handle cases where 'Opleiding' query param is missing
        if (!queryParams.Opleiding && isCategoryFiltered) {
          populateDropdownFromItems(
            opleidingSelect,
            items,
            queryParams.Categorie,
            'Kies een optie...'
          );
        }

        // Handle cases where 'Categorie' query param is missing
        if (!queryParams.Categorie) {
          populateDropdownFromItems(categorySelect, items, null, 'Kies een optie...');
        }
      }

      // Helper to populate dropdown from items
      function populateDropdownFromItems(dropdown, items, filterValue, placeholder) {
        dropdown.innerHTML = '';
        dropdown.appendChild(createPlaceholder(placeholder));

        items.forEach(({ element }) => {
          const textValue = element.querySelector('[fs-cmsselect-element]');
          if (!filterValue || textValue?.getAttribute('data-category') === filterValue) {
            const optionElement = document.createElement('option');
            optionElement.value =
              textValue.getAttribute('data-value') || textValue.textContent.trim();
            optionElement.textContent = textValue.textContent.trim();
            dropdown.appendChild(optionElement);
          }
        });
      }

      // Populate fields and apply filtering on page load
      const queryParams = getQueryParams();
      applyCascadingFilters(queryParams);
    },
  ]);
</script>

Hi Luis,

Thank you for sending the new script. I think we are very close now! When you click on a query parameter URL, the first and second choices are locked, which works great. However, the third choice is automatically set to the placeholder, even when the query parameter is correctly filled for the third option.

Another issue occurs when you open the page without a query parameter. The options that should be loaded for the first select field are not visible. Instead, it starts with the placeholder, and if you click on the select field, the options of the second select field are loaded into the first.

Lastly, the filtering is not working for the second and third select fields.

Here is a link to the page: Schrijf je In voor een Opleiding bij Vidarte | Ontwikkeling Start Hier

I’m looking forward to hear from you!

Best regards,
Micky

Hello Micky!

Apologies for the oversight, I did not test the script thoroughly enough.

Can you please test this on your end? This seems to work on both the query param URL and the clean URL.

Please let me know if I missed anything!

<script>
      window.fsAttributes = window.fsAttributes || [];
      window.fsAttributes.push([
        'cmsselect',
        (listInstances) => {
          console.log('cmsselect successfully loaded!');

          const eventSelect = document.querySelector('[fs-cmsselect-element="select"]');
          const opleidingSelect = document.querySelector('[fs-cmsselect-element="select-2"]');
          const startdatumSelect = document.querySelector('[fs-cmsselect-element="select-3"]');

          const listInstance = listInstances[1];
          const startdatumListInstance = listInstances[2];

          const { items } = listInstance;
          const { items: startdatumItems } = startdatumListInstance;

          function getQueryParams() {
            return Object.fromEntries(new URLSearchParams(window.location.search).entries());
          }

          function populateFormFields() {
            const queryParams = getQueryParams();

            for (const [param, value] of Object.entries(queryParams)) {
              const formField = document.querySelector(`[name="${param}"]`);

              if (formField) {
                if (formField.tagName === 'SELECT') {
                  const optionToSelect = Array.from(formField.options).find(
                    (option) => option.value === value || option.textContent.trim() === value
                  );
                  if (optionToSelect) {
                    optionToSelect.selected = true;
                  }
                  if (formField.name !== 'Startdatum') {
                    formField.disabled = true;
                  }
                }

                let querySelectValue = opleidingSelect.value;
                console.log(querySelectValue);
                const filteredItems = startdatumItems.filter(({ element }) => {
                  if (!querySelectValue) return true;
                  const textValue = element.querySelector('[fs-cmsselect-element]');
                  return textValue?.getAttribute('data-category') === querySelectValue.trim();
                });

                startdatumSelect.innerHTML = '';

                filteredItems.forEach(({ element }) => {
                  const textValue = element.querySelector('[fs-cmsselect-element]');
                  if (textValue) {
                    const optionElement = document.createElement('option');
                    optionElement.value = optionElement.textContent = textValue.textContent.trim();
                    startdatumSelect.appendChild(optionElement);
                  }
                });
              }
            }
          }

          const createPlaceholder = (text) => {
            const placeholder = document.createElement('option');
            placeholder.value = '';
            placeholder.textContent = text;
            placeholder.selected = true;
            return placeholder;
          };

          eventSelect.addEventListener('change', ({ target }) => {
            const selectValue = target.value;

            const filteredItems = items.filter(({ element }) => {
              if (!selectValue) return true;
              const textValue = element.querySelector('[fs-cmsselect-element]');
              return textValue?.getAttribute('data-category') === selectValue.trim();
            });

            opleidingSelect.innerHTML = '';
            opleidingSelect.appendChild(createPlaceholder('Kies een optie...'));

            filteredItems.forEach(({ element }) => {
              const textValue = element.querySelector('[fs-cmsselect-element]');
              if (textValue) {
                const optionElement = document.createElement('option');
                optionElement.value = optionElement.textContent = textValue.textContent.trim();
                opleidingSelect.appendChild(optionElement);
              }
            });
          });

          opleidingSelect.addEventListener('change', ({ target }) => {
            const selectValue = target.value;

            const filteredItems = startdatumItems.filter(({ element }) => {
              if (!selectValue) return true;
              const textValue = element.querySelector('[fs-cmsselect-element]');
              return textValue?.getAttribute('data-category') === selectValue.trim();
            });

            startdatumSelect.innerHTML = '';
            startdatumSelect.appendChild(createPlaceholder('Kies een optie...'));

            filteredItems.forEach(({ element }) => {
              const textValue = element.querySelector('[fs-cmsselect-element]');
              if (textValue) {
                const optionElement = document.createElement('option');
                optionElement.value = optionElement.textContent = textValue.textContent.trim();
                startdatumSelect.appendChild(optionElement);
              }
            });
          });
          populateFormFields();
        },
      ]);
    </script>