CMS filter event/callback function for when a list has been filtered

Hey there,

I’m trying to make a somewhat complex dynamic calendar that also works with cms filter.

Basically I have a list of events in their respective categories sorted by month and year - every new month gets a new header separator and all events in that month get listed under it as a visual subgroup.

Now I’ve managed to get the cms filter going with date inputs etc. But I just can’t get the header reset function to work as intended.

I’ve tried running a function based on field input and click

<!-- month separation -->
<script>
  let headerText = 0;
  let headerYear = 0;
  let template = $(".date_template").find(".date_header");
  $(".date_template").hide();

  function resetHeaders() {
    $(".cms_list-horizontal").find(".date_header").remove();
    $(".cms_item").each(function () {
      let currentHeaderText = $(this).find(".month").text();
      let currentYearText = $(this).find(".year").text();
      if (headerText !== currentHeaderText || headerYear !== currentYearText) {
        headerText = currentHeaderText;
        headerYear = currentYearText;
        let clone = template.clone().insertBefore($(this));
        clone.find(".header_title").text(headerText);
        clone.find(".year_title").text(headerYear);
      }
    });
  }
  resetHeaders();

  function handleInputChange() {
    console.log("handleInputChange called");
    setTimeout(() => {
      headerText = 0;
      headerYear = 0;
      resetHeaders();
    }, 600);
  }

  $(document).ready(function() {
    $(".form_toplabel_field_input").on("input", handleInputChange);
    $(".checkbox_full").on("click", handleInputChange);
  });

</script>

But it just doesn’t trigger every time I click. I’ve inspected the issue in the console and the function doesn’t get called.

I’ve also tried doing the same but checking for URL parameter changes(I’m running query param attributes) - and again it almost works but for some instances even if there’s a change in the URL, I don’t get a call for the function.

I think in some cases the function might be running before the filtering is complete.

So technically this would all be easy to solve if I had a way to monitor when the filtering event was finished and then just run the function afterwards.

Now obviously I can brute force the addition of this elements in some other way but it wouldn’t be elegant and I need to remove the visual stutter. So I’ve introduced a cms filter duration of 1000ms. I tried changing the delay value of my function manually, but it seems like its just redundant guesswork and didn’t yield any results.

here’s a link to the staging page there’s only one cms item currently

and a view-only for webflow

Hey @boris! I’ve wrapped the function with the CMS Filter Callback. I believe this is what you were looking to do.

Can you please test and let me know how it goes?

<!-- month separation -->
<script>
  window.fsAttributes = window.fsAttributes || [];
  window.fsAttributes.push([
    'cmsfilter',
    (filterInstances) => {
      console.log('cmsfilter Successfully loaded!');

      let headerText = 0;
      let headerYear = 0;
      let template = $('.date_template').find('.date_header');
      $('.date_template').hide();

      function resetHeaders() {
        $('.cms_list-horizontal').find('.date_header').remove();
        $('.cms_item').each(function () {
          let currentHeaderText = $(this).find('.month').text();
          let currentYearText = $(this).find('.year').text();
          if (headerText !== currentHeaderText || headerYear !== currentYearText) {
            headerText = currentHeaderText;
            headerYear = currentYearText;
            let clone = template.clone().insertBefore($(this));
            clone.find('.header_title').text(headerText);
            clone.find('.year_title').text(headerYear);
          }
        });
        console.log('headers reset!');
      }

      const [filterInstance] = filterInstances;

      resetHeaders();

      filterInstance.listInstance.on('renderitems', (renderedItems) => {
        console.log(renderedItems);
        resetHeaders();
      });
    },
  ]);
</script>

Hey @Support-Luis ,

Thanks for the response. Unfortunately, the code you provided isn’t yielding the results I need. The headers are being reset when I load the page but once I apply a filter the header element completely disappears.

Here’s a link where you can inspect the console response for yourself

Thanks in advance!

https://sitostyleguide.webflow.io/kursove

Hey @boris, can you please share a quick video on what you expect to achieve? I will take this as a guide

Hey @Support-Luis thanks for the support

Here’s a loom that describes the intended use case I did some repurposing of the code you provided and almost got the script to work just some minor details that I can’t wrap my head around.

Here’s the link to the loom

The code I’m using for this:

<!-- month separation -->
<script>
  let headerText = 0;
  let headerYear = 0;
  let template = $(".date_template").find(".date_header");
  $(".date_template").hide();

  function resetHeaders() {
    $(".cms_list-horizontal").find(".date_header").remove();
    $(".cms_item").each(function () {
      let currentHeaderText = $(this).find(".month").text();
      let currentYearText = $(this).find(".year").text();
      if (headerText !== currentHeaderText || headerYear !== currentYearText) {
        headerText = currentHeaderText;
        headerYear = currentYearText;
        let clone = template.clone().insertBefore($(this));
        clone.find(".header_title").text(headerText);
        clone.find(".year_title").text(headerYear);
      }
    });
  }

  function handleInputChange() {
    console.log("handleInputChange called");
    setTimeout(() => {
      headerText = 0;
      headerYear = 0;
      resetHeaders();
    }, 600); // Increase the delay to ensure CMS items are fully loaded
  }

  $(document).ready(function() {
    $(".form_toplabel_field_input").on("input", handleInputChange);
    $(".checkbox_full").on("click", handleInputChange);

    // Callback for Finsweet CMS filter completion
    window.fsAttributes = window.fsAttributes || [];
    window.fsAttributes.push([
      'cmsfilter',
      (filterInstances) => {
        console.log('cmsfilter Successfully loaded!');
        // Attach a callback to run handleInputChange after filtering is done
        filterInstances.forEach(instance => {
          instance.listInstance.on('renderitems', () => {
            handleInputChange();
          });
        });
      }
    ]);
  });
</script>

And a staging link to the website