> For the complete documentation index, see [llms.txt](https://docs.buzzy.buzz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.buzzy.buzz/the-building-blocks/code-widget-custom-code/examples/contact-age-filter.md).

# Contact Age Filter

This example demonstrates how to create a custom age range filter for a contacts app using the new `filterMicroappView` async API.

## Scenario

You have a contacts table with `name` and `age` fields, and you want to create a custom search panel that allows filtering contacts by age range.

## Implementation

```html
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        .filter-container {
            display: flex;
            gap: 10px;
            align-items: center;
            padding: 20px;
            font-family: Arial, sans-serif;
        }
        .filter-input {
            padding: 8px;
            border: 1px solid #ccc;
            border-radius: 4px;
            width: 80px;
        }
        .filter-button {
            padding: 8px 16px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        .filter-button:hover {
            background: #0056b3;
        }
        .clear-button {
            padding: 8px 16px;
            background: #6c757d;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-left: 5px;
        }
        .clear-button:hover {
            background: #545b62;
        }
    </style>
</head>
<body>
    <div class="filter-container">
        <label>Age from:</label>
        <input type="number" id="minAge" class="filter-input" value="20" min="0" max="120">
        <label>to:</label>
        <input type="number" id="maxAge" class="filter-input" value="30" min="0" max="120">
        <button onclick="applyFilter()" class="filter-button">Filter</button>
        <button onclick="clearFilter()" class="clear-button">Clear</button>
    </div>

    <script>
        let buzzyFrameAPI;
        let contactsTableID;

        (async function initializeAPI() {
            try {
                buzzyFrameAPI = new BuzzyFrameAPI();
                const { resourceJSON } = await buzzyFrameAPI.initialise();
                
                contactsTableID = resourceJSON.children?.find(
                    child => child.title === 'Contacts'
                )?._id;
                
                if (!contactsTableID) {
                    console.error('Contacts table not found in resourceJSON');
                }
            } catch (error) {
                console.error('Failed to initialize BuzzyFrameAPI:', error);
            }
        })();

        async function applyFilter() {
            if (!buzzyFrameAPI || !contactsTableID) {
                console.error('API not initialized or contacts table not found');
                return;
            }

            const minAge = parseInt(document.getElementById('minAge').value);
            const maxAge = parseInt(document.getElementById('maxAge').value);

            if (isNaN(minAge) || isNaN(maxAge)) {
                alert('Please enter valid age values');
                return;
            }

            if (minAge > maxAge) {
                alert('Minimum age cannot be greater than maximum age');
                return;
            }

            try {
                await buzzyFrameAPI.filterMicroappView({
                    microAppID: contactsTableID,
                    viewFilters: [
                        { age: { $gte: minAge } },
                        { age: { $lte: maxAge } }
                    ],
                    viewFilterIsMongoQuery: true,
                    filterContext: 'contact-age-filter'
                });
                console.log(`Applied age filter: ${minAge} to ${maxAge}`);
            } catch (error) {
                console.error('Failed to apply filter:', error);
            }
        }

        async function clearFilter() {
            if (!buzzyFrameAPI || !contactsTableID) {
                console.error('API not initialized or contacts table not found');
                return;
            }

            try {
                await buzzyFrameAPI.filterMicroappView({
                    microAppID: contactsTableID,
                    viewFilters: [],
                    viewFilterIsMongoQuery: true,
                    filterContext: 'contact-age-filter'
                });
                console.log('Cleared age filter');
            } catch (error) {
                console.error('Failed to clear filter:', error);
            }
        }
    </script>
</body>
</html>
```

## Key Points

### Modern Async API Approach

* Uses the new `filterMicroappView` async API instead of deprecated `filterview` postMessage
* Initializes BuzzyFrameAPI at the top level before React components
* Uses proper error handling with try/catch blocks

### MongoDB Query Syntax

* Uses `$gte` (greater than or equal) and `$lte` (less than or equal) operators
* Supports complex filtering with multiple conditions
* Set `viewFilterIsMongoQuery: true` to enable MongoDB operators

### User Experience Features

* Input validation to ensure valid age ranges
* Clear filter functionality to remove all filters
* Responsive design with hover effects
* Error handling with console logging

### Filter Context

* Uses `filterContext: 'contact-age-filter'` to identify this specific filter
* Allows multiple filters to coexist without conflicts
* Helps with debugging and filter management

## Migration from Deprecated filterview

If you're migrating from the old `filterview` postMessage approach:

**Old approach (deprecated):**

```javascript
window.parent.postMessage({
    from: 'buzzy-iframe',
    action: 'filterview',
    body: filterParams,
    frameToken: frameToken
}, '*');
```

**New approach (recommended):**

```javascript
await buzzyFrameAPI.filterMicroappView({
    microAppID: contactsTableID,
    viewFilters: filterParams.viewFilters,
    viewFilterIsMongoQuery: true,
    filterContext: 'your-filter-context'
});
```

## Testing the Example

1. Create a contacts app with `name` (text) and `age` (number) fields
2. Add some sample contacts with different ages
3. Add this code widget to a screen that displays the contacts table
4. Test filtering by different age ranges
5. Verify that the "Clear" button removes all filters
