# Filtering with dynamic radius data

**URL:** https://forum.finsweet.com/t/filtering-with-dynamic-radius-data/6514
**Category:** Attributes
**Tags:** cmsfilter, attributes-v2
**Created:** [December 4, 2025, 1:59pm UTC](https://forum.finsweet.com/t/filtering-with-dynamic-radius-data/6514 "2025-12-04T13:59:31Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![talnt.company](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.finsweet.com/talnt.company/32/5675_2.png) [@talnt.company](https://forum.finsweet.com/u/talnt.company)
#### Post date: [December 4, 2025, 1:59pm UTC](https://forum.finsweet.com/t/filtering-with-dynamic-radius-data/6514/1 "2025-12-04T13:59:31Z")

</div>

### **What we’re trying to do**

We want to filter CMS items based on a **dynamic radius calculation** :

- User selects a ZIP code via Google Maps Autocomplete

- We calculate the distance from that ZIP to each CMS item (lat/lng stored as CMS fields → added as `data-lat`, `data-lng`, `data-radius` on each item)

- Every item that is within the radius has a textfield that is filled via js with “Ja” (calculated dynamically)

- A checkbox should act as a **toggle** to show only items within their individual radius.

- The checkbox is set as true as soon as a zip code is entered - Hoping that the finsweet filter is kicking in and filtering the list (disclaimer: it doesnt)

But **List Filter v2 does not respond** to the checkbox being checked:

- No filtering is triggered

- The list does not update

### 

Is there a correct way to:

1. Use a checkbox as a **custom trigger** for filtering (not tied to a CMS field)?

2. Tell List Filter v2 to **re-run filtering** when this checkbox changes?

3. Integrate a custom filtering condition (radius logic) with the List Filter system?

Any guidance on how to properly register a checkbox as a filter trigger — or how to manually make List Filter re-filter — would be super appreciated.

URL: [https://talnt-2025.webflow.io/](https://talnt-2025.webflow.io/)

[![image](https://europe1.discourse-cdn.com/flex013/uploads/finsweet1/original/2X/d/d5e8ddc8142eff4e319da1f532f6642538437ea0.png)](https://europe1.discourse-cdn.com/flex013/uploads/finsweet1/original/2X/d/d5e8ddc8142eff4e319da1f532f6642538437ea0.png "image")

Thanks for you support 🙂  
Sarah

---

<div class="post-metadata">

### Author: ![Support-Luis](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.finsweet.com/support-luis/32/53_2.png) [@Support-Luis](https://forum.finsweet.com/u/Support-Luis)
#### Post date: [December 6, 2025, 11:59am UTC](https://forum.finsweet.com/t/filtering-with-dynamic-radius-data/6514/2 "2025-12-06T11:59:00Z")

</div>

Required Script in head:

```auto
<script async type="module"
src="https://cdn.jsdelivr.net/npm/@finsweet/attributes@2/attributes.js"
fs-list
></script>

```

Checkbox

`<input type="checkbox" id="radiusCheckbox" fs-list-field="radius-toggle">`

CMS List wrapper

```auto
<div fs-list="list">
  <!-- your CMS items -->
</div>

```

Filters wrapper

```auto
<form fs-list="filters">
  <!-- radiusCheckbox lives here -->
</form>

```

Each CMS Item (store lat/lng + radius)

```auto
<div class="item"
     data-lat="48.12345"
     data-lng="11.56789"
     data-radius="30">
  <!-- Your job card content -->
</div>

```

Complete radius filtering script

```auto
<script>
window.FsAttributes = window.FsAttributes || [];
window.FsAttributes.push([
  'list',
  (listInstances) => {
    const list = listInstances[0];

    // The checkbox toggle element
    const radiusCheckbox = document.getElementById("radiusCheckbox");

    // Global user location variables (fill these when ZIP is selected)
    let userLat = null;
    let userLng = null;

    // Haversine distance (km)
    function calculateDistance(lat1, lon1, lat2, lon2) {
      const R = 6371;
      const dLat = (lat2 - lat1) * Math.PI / 180;
      const dLon = (lon2 - lon1) * Math.PI / 180;

      const a =
        Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.cos(lat1 * Math.PI/180) *
        Math.cos(lat2 * Math.PI/180) *
        Math.sin(dLon/2) * Math.sin(dLon/2);

      return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)));
    }

    // ---- 🔥 Dynamic filter logic (THIS is the magic) ----
    list.dynamicFilters.push((item) => {
      // Checkbox off → show all items
      if (!radiusCheckbox.checked) return true;

      // User has not selected a ZIP → show all items
      if (userLat === null || userLng === null) return true;

      const el = item.element;

      const itemLat = parseFloat(el.dataset.lat);
      const itemLng = parseFloat(el.dataset.lng);
      const itemRadius = parseFloat(el.dataset.radius);

      const distance = calculateDistance(userLat, userLng, itemLat, itemLng);

      return distance <= itemRadius;
    });

    // ---- When checkbox changes → reapply all filters ----
    radiusCheckbox.addEventListener("change", () => {
      list.runFilters();
    });

    // ---- ZIP selection handler (Google Autocomplete) ----
    window.setUserLocationFromZip = function(lat, lng) {
      userLat = lat;
      userLng = lng;

      // Auto-enable radius checkbox (optional)
      radiusCheckbox.checked = true;

      // Re-filter list based on new user coordinates
      list.runFilters();
    };

  }
]);
</script>

```

How to use

After user picks a ZIP code from Google Autocomplete, run:

```auto
setUserLocationFromZip(lat, lng);

```

This will:

- update userLat / userLng
- automatically enable the checkbox (optional)
- re-run all List Filter logic
- filter items according to your radius

---

<div class="post-metadata">

### Author: ![talnt.company](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.finsweet.com/talnt.company/32/5675_2.png) [@talnt.company](https://forum.finsweet.com/u/talnt.company)
#### Post date: [December 7, 2025, 8:49pm UTC](https://forum.finsweet.com/t/filtering-with-dynamic-radius-data/6514/3 "2025-12-07T20:49:01Z")

</div>

Thanks for your answer, however this seems to not be working unfortunately. I receive the following error:

Uncaught TypeError: list.runFilters is not a function

Are you sure fs-list=“list” & fs-list=“filters” is correct? The Finsweet V2 Doc uses fs-list-element=”list” and fs-list-element=”list”

Thanks again!

---

<div class="post-metadata">

### Author: ![jesse.muiruri](https://dub1.discourse-cdn.com/flex013/user_avatar/forum.finsweet.com/jesse.muiruri/32/5523_2.png) [@jesse.muiruri](https://forum.finsweet.com/u/jesse.muiruri)
#### Post date: [December 8, 2025, 11:06am UTC](https://forum.finsweet.com/t/filtering-with-dynamic-radius-data/6514/4 "2025-12-08T11:06:42Z")

</div>

Hi @talnt.company

You are absolutely correct, I sort of mixed it up

Sorry & let’s have another go at this

The list wrapper

```auto
<div fs-list-element="list">
  <!-- CMS Items -->
</div>

```

The filters wrapper

```auto
<form fs-list-element="filters">
  <!-- checkbox lives here -->
</form>

```

The cms item

```auto
<div class="item"
     data-lat="48.12345"
     data-lng="11.12345"
     data-radius="50">
</div>

```

For the filtering

```auto
<script>
window.FsAttributes = window.FsAttributes || [];
window.FsAttributes.push([
  'list',
  (listInstances) => {
    const listInstance = listInstances[0];

    const checkbox = document.getElementById("radiusCheckbox");
    let userLat = null;
    let userLng = null;

    // Haversine
    function calculateDistance(lat1, lon1, lat2, lon2) {
      const R = 6371;
      const dLat = (lat2 - lat1) * Math.PI / 180;
      const dLon = (lon2 - lon1) * Math.PI / 180;
      const a =
        Math.sin(dLat/2) ** 2 +
        Math.cos(lat1 * Math.PI / 180) *
        Math.cos(lat2 * Math.PI / 180) *
        Math.sin(dLon/2) ** 2;
      return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)));
    }

    // 🔥 Dynamic filter logic using List Filter V2's internal filtering
    const radiusFilter = (items) => {
      // If toggle off or no ZIP → show all
      if (!checkbox.checked || !userLat || !userLng) return items;

      return items.filter((item) => {
        const el = item.element;
        const lat = parseFloat(el.dataset.lat);
        const lng = parseFloat(el.dataset.lng);
        const radius = parseFloat(el.dataset.radius);

        const distance = calculateDistance(userLat, userLng, lat, lng);

        return distance <= radius;
      });
    };

    // Register custom filter
    listInstance.addFilter(radiusFilter);

    // Checkbox → re-filter
    checkbox.addEventListener("change", () => listInstance.filter());

    // Called when ZIP is selected
    window.setUserLocationFromZip = (lat, lng) => {
      userLat = lat;
      userLng = lng;
      checkbox.checked = true;
      listInstance.filter();
    };
  }
]);
</script>

```

Of course the checkbox remains as is

```auto
<input type="checkbox" id="radiusCheckbox" fs-list-field="radius-toggle">

```

Please let me know how it goes

Thanks
