Sort with Dynamic Text Content

I’m having issues using CMS Sort with a dynamic text content that is being changed when an action is made.

For this case, it is calculating distance based on a person’s address and the inputted address/postal code.

Here is the staging link:
https://ctcplayground01.webflow.io/

Would love to know what is the issue and if there is a solution.

Hey @info2! Could you give me a search example I could try? All locations appear as 0 miles for me.

Sorry it’s only postal code at the moment. Try any postal code and it should populate @Support-Luis

Hey @info2! I’m sorry but I can not notice any issue with the setup… I can input an initial postal code and click on “Nearest Person to me” and the smallest distance is the top result. I can enter another postal code from another state and results are sorted upon clicking again.

Could you please share a loom on what the issue is?

Hey @Support-Luis, here is a loom briefly outlining the issue with CMS Sort and a new staging link to review.

https://ctcplayground01.webflow.io/home-copy

Awesome, thanks!

Here is a quick video from my end

The original page is not using CMS Sort to reorder from smallest to largest number, the new link I gave is using CMS Sort but is not working which I need help to figure out why.

Hope that helps clarify @Support-Luis

Any insight on how we can make this work @Support-Luis?

Hey @info2! I’m afraid I have not managed to get it to work yet. I’ll get back to you once I find the best solution :wink:

1 Like

Hey @info2! Can you test this code?

// This file was generated by Slater.app - Prototype 2.js
window.fsAttributes = window.fsAttributes || [];
window.fsAttributes.push([
  'cmssort',
  (listInstances) => {
    // ------------------------
    // Global Variables //
    // ------------------------

    const [listInstance] = listInstances;
    const inputElement = document.querySelector('[f-el="input"]'); // Google Maps Input
    const personElements = Array.from(document.querySelectorAll('[f-el="item"]')); // Collection Items
    const formElement = document.querySelector('[f-el="form"]'); // Form Filter
    const listElement = document.querySelector('[f-el="list"]'); // Collection List
    const clearButton = formElement.querySelector('[fs-cmsfilter-element="clear"]'); // Filter Clear Button

    let currentState = null;

    const applyAutocomplete = (inputElement) => {
      const autocomplete = new google.maps.places.Autocomplete(inputElement, {
        types: ['(regions)'],
        componentRestrictions: { country: 'us' },
      });

      autocomplete.setFields(['address_components', 'geometry']);

      autocomplete.addListener('place_changed', function () {
        const place = autocomplete.getPlace();
        if (place.address_components) {
          let zipCode = null;
          let state = null;
          for (const component of place.address_components) {
            if (component.types.includes('postal_code')) {
              zipCode = component.short_name;
            }
            if (component.types.includes('administrative_area_level_1')) {
              state = component.long_name;
            }
          }
          if (zipCode) {
            calculateDistances(zipCode);
          }
          if (state) {
            checkStateFilter(state);
            currentState = state;
          }
        }
      });

      // ------------------------
      // Clearing Input via Empty Input or Manual Click //
      // ------------------------
      inputElement.addEventListener('input', function () {
        const input = this.value.trim();
        if (input === '') {
          clearButton?.click();
          resetDistanceAndDuration();
          clearDistanceAttributes();
        } else if (/^\d{5}$/.test(input)) {
          calculateDistances(input);
        }
      });
    };

    clearButton.addEventListener('click', () => {
      resetDistanceAndDuration();
      clearDistanceAttributes();
      inputElement.value = '';
    });

    // ------------------------
    // Calculate Distance via Google Maps JS //
    // ------------------------
    function calculateDistances(zipCode) {
      const geocoder = new google.maps.Geocoder();
      const distanceService = new google.maps.DistanceMatrixService();

      geocoder.geocode({ address: zipCode }, function (results, status) {
        if (status === 'OK' && results[0]) {
          const origin = results[0].geometry.location;

          personElements.forEach((person) => {
            const address = person.querySelector('[f-el="address"]').textContent;

            distanceService.getDistanceMatrix(
              {
                origins: [origin],
                destinations: [address],
                travelMode: 'DRIVING',
                unitSystem: google.maps.UnitSystem.IMPERIAL,
              },
              function (response, status) {
                if (status === 'OK') {
                  const distance = response.rows[0].elements[0].distance;
                  const duration = response.rows[0].elements[0].duration;

                  const distanceInMiles = (distance.value / 1609.34).toFixed(2);
                  let durationInMinutes = Math.round(duration.value / 60);
                  let durationHours = Math.floor(durationInMinutes / 60);
                  let durationDays = Math.floor(durationHours / 24);
                  durationHours %= 24;
                  durationInMinutes %= 60;

                  let durationText = `${durationInMinutes} mins`;
                  if (durationHours > 0) {
                    durationText = `${durationHours} hr ${durationText}`;
                  }
                  if (durationDays > 0) {
                    durationText = `${durationDays} day ${durationText}`;
                  }

                  person
                    .querySelectorAll('[f-el="distance"]')
                    .forEach((el) => (el.textContent = `${distanceInMiles}`));
                  person
                    .querySelectorAll('[f-el="min"]')
                    .forEach((el) => (el.textContent = `${durationText}`));

                  // Store the distance in a data attribute for sorting
                  person.setAttribute('data-distance', distanceInMiles);
                }
                window.fsAttributes.cmssort.destroy();  // needed to restar CMS Sort
                window.fsAttributes.cmssort.init();
              }
            );
          });
        }
      });
    }

    // ------------------------
    // Autoclick on CMS Filter checkbox with States
    // ------------------------
    function checkStateFilter(state) {
      if (formElement) {
        const stateElements = formElement.querySelectorAll('[fs-cmsfilter-field="state"]');
        stateElements.forEach((stateElement) => {
          const stateName = stateElement.textContent.trim();
          let checkbox = stateElement.previousElementSibling;
          if (stateName === state) {
            if (!checkbox.checked) {
              checkbox.click();
            }
          } else if (stateName === currentState) {
            if (checkbox.checked) {
              checkbox.click();
            }
          }
        });
      }
    }

    // ------------------------
    // Reset Functions //
    // ------------------------
    function resetDistanceAndDuration() {
      personElements.forEach((person) => {
        person.querySelectorAll('[f-el="distance"]').forEach((el) => (el.textContent = '0 miles'));
        person.querySelectorAll('[f-el="min"]').forEach((el) => (el.textContent = '0 mins'));
      });
    }

    function clearDistanceAttributes() {
      personElements.forEach((person) => {
        person.removeAttribute('data-distance');
      });
    }

    // ------------------------
    // Call Functions //
    // ------------------------
    applyAutocomplete(inputElement);
    resetDistanceAndDuration();
  },
]);

This works! Now having issues with CMS Load if the item are paginated @Support-Luis

Hey @info2! Issues with which part of the code?

I added CMS Load and having issues where it doesn’t hide or show the pagination buttons sometimes when I clear after filtering. @Support-Luis

Could you record a quick video on how to reproduce the issue?

1 Like

Here you go @Support-Luis

You’ll see a few issues:

  • Only calculation is being done on the first page of the pagination
  • Once cleared/reset, pagination buttons are gone permanently
  • Require refresh to restore pagination

Thanks! I’ll take a look :muscle:

1 Like

Hey @info2! Seems that the lines we added to destroy and init CMS Sort are introducing the bug. If you comment them out everything should work normally except the sorting of the items.

We can ditch the Attributes sorting and create our own sorting function instead.

Let me know what you think

Sure that would work as well. Is there no way to make CMS Load work then? @Support-Luis

CMS Load will work and it should work at the moment if you just comment on these two lines

window.fsAttributes.cmssort.destroy(); // needed to restar CMS Sort
window.fsAttributes.cmssort.init();

I’ll work on integrating the sorting function and get back to you :wink:

1 Like