Custom HTML filters
🎠 Create any filtering experience you like
Custom HTML Filters are a powerful feature that allows developers to create completely customized filtering interfaces for Directual Web Components (Tables, Cards, etc.). Instead of being limited to the built-in filter components, you can write your own HTML, CSS, and JavaScript to create any filtering experience you need.
What are HTML Filters?
HTML Filters are custom user interfaces that replace the standard Directual filtering system. They consist of:
Custom HTML: Your own form elements, layouts, and styling
Interactive JavaScript: Logic to handle user interactions and generate filters
DQL Integration: Seamless connection to Directual's query language
Real-time Updates: Instant filtering as users interact with your interface
Key Benefits
✅ Complete Design Freedom: Create filters that match your exact design requirements ✅ Advanced Interactions: Build complex filtering logic with multiple conditions ✅ Custom Components: Use any UI library or custom components you prefer ✅ Business Logic: Implement domain-specific filtering rules and validations ✅ User Experience: Design intuitive interfaces tailored to your users' needs
How It Works
Enable Custom Filters: Set
customHTMLfilters: truein your component propsProvide HTML Content: Pass your custom HTML/CSS/JS in
customHTMLfiltersContentUse the API: Access
window.DirectualFilterto interact with the filtering systemGenerate DQL: Create Directual Query Language strings to filter data
Apply Filters: Call
window.DirectualFilter.emit(dql)to update the view
Use Cases
E-commerce: Product search with price ranges, categories, ratings, and availability
Real Estate: Property filters with location maps, price ranges, and feature checkboxes
CRM: Contact filtering with tags, date ranges, and custom field combinations
Analytics: Data filtering with date pickers, metric selectors, and comparison tools
Content Management: Article filtering with categories, authors, and publication dates
AI Prompt for Custom Filter Development
You are an expert web developer creating custom HTML filters for Directual Web Components. Your task is to create interactive filter interfaces that integrate with the Directual filtering system.
**CRITICAL: Date Formatting Requirements**
- All dates in DQL queries MUST be in ISO 8601 format
- Use formats like: `'2000-04-09T'`, `'2000-04-09T14:30:00Z'`, or `'2000-04-09T14:30:00.000Z'`
- Convert user input dates to ISO format before generating DQL
- Example: User selects "April 9, 2000" → convert to `'2000-04-09T'` in DQL
### Technical Requirements
**API Contract:**
- Use `window.DirectualFilter.props` to access current state and available fields
- Call `window.DirectualFilter.emit(dqlString, sortOptions)` to apply filters and sorting
- DQL (Directual Query Language) format: `'fieldName' operator 'value'`
- Sort options: `{field: 'fieldName', direction: 'asc'|'desc'}` or `'fieldName:asc'`
**Available Data:**
```javascript
window.DirectualFilter.props = {
currentFilter: string, // Current DQL filter
currentSort: object|string|null, // Current sorting (object: {field, direction} or string: "field:direction")
fields: Array<{ // Available fields for filtering
key: string, // Field system name
value: string // Field display name
}>,
lang: string, // Current language
dict: object // Localization dictionary
}
```
**DQL Operators:**
- `like` - partial text match
- `=` - exact match
- `>=`, `<=`, `>`, `<` - numeric/date comparisons
- `AND`, `OR` - logical operators
**DQL Examples:**
- `'title' like 'sun' AND 'year' < 1950`
- `('title' like 'sun' AND 'year' < 1950) OR 'is_good' = 'true'`
- `'birth_date' <= '2000-04-09T'`
- `'price' >= 100 AND 'category' = 'electronics'`
**Important Notes:**
- **Dates must be in ISO format**: Use ISO 8601 format like `'2000-04-09T'` or `'2000-04-09T14:30:00Z'`
- **Numbers are NOT quoted**: Use bare numbers like `100`, `1950` (no quotes)
- **Strings and dates ARE quoted**: Text and dates must be in single quotes `'text'`, `'2000-04-09T'`
- **Field names must be quoted**: Always use single quotes around field names `'fieldName'`
### Filter Design Guidelines
**[DESCRIBE YOUR FILTER REQUIREMENTS HERE]**
*Example: Create a modern, responsive filter interface with search inputs, dropdown selectors, and date pickers. Use Bootstrap-style components with blue (#007bff) primary color and clean typography.*
### Implementation Pattern
1. **HTML Structure**: Create form elements with unique IDs
2. **JavaScript Functions**: Implement filter logic and DQL generation
3. **Event Handlers**: Connect UI interactions to `window.DirectualFilter.emit()`
4. **State Management**: Handle filter clearing and validation
### Example Code Template
```html
<div style="padding: 20px; border: 1px solid #ddd; border-radius: 8px;">
<h4>Custom Filters</h4>
<!-- Text Search -->
<div style="margin-bottom: 15px;">
<label>Search Text:</label>
<input type="text" id="textSearch" placeholder="Enter search term...">
<button onclick="applyTextFilter()">Apply</button>
</div>
<!-- Numeric Range -->
<div style="margin-bottom: 15px;">
<label>Number Range:</label>
<input type="number" id="minNumber" placeholder="Min">
<input type="number" id="maxNumber" placeholder="Max">
<button onclick="applyNumberFilter()">Filter</button>
</div>
<!-- Sorting -->
<div style="margin-bottom: 15px;">
<label>Sort by:</label>
<select id="sortField">
<option value="">No sorting</option>
<option value="fieldName">Field Name</option>
<option value="numberField">Number Field</option>
</select>
<select id="sortDirection">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
<button onclick="applySorting()">Sort</button>
</div>
<!-- Actions -->
<button onclick="clearFilters()">Clear All</button>
</div>
<script>
function applyTextFilter() {
const value = document.getElementById('textSearch').value;
if (value) {
const dql = "'fieldName' like '" + value + "'";
const currentSort = getCurrentSort();
window.DirectualFilter.emit(dql, currentSort);
}
}
function applyNumberFilter() {
const min = document.getElementById('minNumber').value;
const max = document.getElementById('maxNumber').value;
let conditions = [];
if (min) conditions.push("'numberField' >= '" + min + "'");
if (max) conditions.push("'numberField' <= '" + max + "'");
const dql = conditions.join(' AND ');
const currentSort = getCurrentSort();
window.DirectualFilter.emit(dql, currentSort);
}
function applySorting() {
const field = document.getElementById('sortField').value;
const direction = document.getElementById('sortDirection').value;
if (field) {
const sortOptions = { field: field, direction: direction };
const currentFilter = getCurrentFilter();
window.DirectualFilter.emit(currentFilter, sortOptions);
}
}
function getCurrentSort() {
const field = document.getElementById('sortField').value;
const direction = document.getElementById('sortDirection').value;
return field ? { field: field, direction: direction } : null;
}
function getCurrentFilter() {
const text = document.getElementById('textSearch').value;
const min = document.getElementById('minNumber').value;
const max = document.getElementById('maxNumber').value;
let conditions = [];
if (text) conditions.push("'fieldName' like '" + text + "'");
if (min) conditions.push("'numberField' >= '" + min + "'");
if (max) conditions.push("'numberField' <= '" + max + "'");
return conditions.join(' AND ');
}
function clearFilters() {
document.getElementById('textSearch').value = '';
document.getElementById('minNumber').value = '';
document.getElementById('maxNumber').value = '';
document.getElementById('sortField').value = '';
window.DirectualFilter.emit('', null);
}
// Initialize on load
setTimeout(() => {
console.log('Available fields:', window.DirectualFilter.props.fields);
}, 100);
</script>
```
### Best Practices
1. **Field Validation**: Check if fields exist before filtering
2. **Error Handling**: Validate user input and DQL syntax
3. **Performance**: Debounce rapid filter changes
4. **UX**: Provide clear feedback and loading states
5. **Accessibility**: Use proper labels and keyboard navigation
### Advanced Features
- **Multi-field filtering**: Combine multiple conditions with AND/OR
- **Dynamic field selection**: Let users choose which fields to filter
- **Preset filters**: Provide common filter combinations
- **Filter history**: Save and restore previous filter states
---
## Simple Example: Product Search Filter
```html
<div class="custom-filter" style="padding: 20px; background: #f8f9fa; border-radius: 8px; font-family: Arial, sans-serif;">
<h3 style="margin-top: 0; color: #333;">🔍 Product Search</h3>
<!-- Product Name Search -->
<div style="margin-bottom: 15px;">
<label style="display: block; font-weight: bold; margin-bottom: 5px;">Product Name:</label>
<input type="text" id="productName"
style="width: 250px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;"
placeholder="Enter product name...">
</div>
<!-- Price Range -->
<div style="margin-bottom: 15px;">
<label style="display: block; font-weight: bold; margin-bottom: 5px;">Price Range:</label>
<input type="number" id="minPrice" placeholder="Min $"
style="width: 100px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; margin-right: 10px;">
<input type="number" id="maxPrice" placeholder="Max $"
style="width: 100px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
</div>
<!-- Category Dropdown -->
<div style="margin-bottom: 15px;">
<label style="display: block; font-weight: bold; margin-bottom: 5px;">Category:</label>
<select id="category" style="width: 200px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
</div>
<!-- Sorting Options -->
<div style="margin-bottom: 15px;">
<label style="display: block; font-weight: bold; margin-bottom: 5px;">Sort by:</label>
<select id="sortBy" style="width: 150px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; margin-right: 10px;">
<option value="">Default</option>
<option value="productName">Name</option>
<option value="price">Price</option>
<option value="category">Category</option>
</select>
<select id="sortOrder" style="width: 120px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
<option value="asc">A → Z / Low → High</option>
<option value="desc">Z → A / High → Low</option>
</select>
</div>
<!-- Action Buttons -->
<div>
<button onclick="searchProducts()"
style="padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px;">
Search Products
</button>
<button onclick="clearSearch()"
style="padding: 10px 20px; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">
Clear
</button>
</div>
<!-- Status Display -->
<div id="filterStatus" style="margin-top: 15px; padding: 10px; background: #e9ecef; border-radius: 4px; display: none;">
<strong>Active Filter:</strong> <span id="currentFilter"></span>
</div>
</div>
<script>
function searchProducts() {
const name = document.getElementById('productName').value;
const minPrice = document.getElementById('minPrice').value;
const maxPrice = document.getElementById('maxPrice').value;
const category = document.getElementById('category').value;
let conditions = [];
// Add name filter
if (name) {
conditions.push("'productName' like '" + name + "'");
}
// Add price range filters
if (minPrice) {
conditions.push("'price' >= '" + minPrice + "'");
}
if (maxPrice) {
conditions.push("'price' <= '" + maxPrice + "'");
}
// Add category filter
if (category) {
conditions.push("'category' = '" + category + "'");
}
// Combine all conditions
const dql = conditions.join(' AND ');
// Get current sorting
const sortBy = document.getElementById('sortBy').value;
const sortOrder = document.getElementById('sortOrder').value;
const sortOptions = sortBy ? { field: sortBy, direction: sortOrder } : null;
// Show current filter
updateFilterStatus(dql, sortOptions);
// Apply filter with sorting
window.DirectualFilter.emit(dql, sortOptions);
console.log('Applied filter:', dql, 'with sorting:', sortOptions);
}
function clearSearch() {
// Clear all inputs
document.getElementById('productName').value = '';
document.getElementById('minPrice').value = '';
document.getElementById('maxPrice').value = '';
document.getElementById('category').value = '';
document.getElementById('sortBy').value = '';
// Hide status
document.getElementById('filterStatus').style.display = 'none';
// Clear filter and sorting
window.DirectualFilter.emit('', null);
console.log('Filters and sorting cleared');
}
function updateFilterStatus(dql, sortOptions) {
const status = document.getElementById('filterStatus');
const current = document.getElementById('currentFilter');
if (dql || sortOptions) {
let statusText = '';
if (dql) statusText += 'Filter: ' + dql;
if (sortOptions) {
if (statusText) statusText += ' | ';
statusText += 'Sort: ' + sortOptions.field + ' ' + sortOptions.direction;
}
current.textContent = statusText;
status.style.display = 'block';
} else {
status.style.display = 'none';
}
}
// Auto-search on Enter key
document.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
searchProducts();
}
});
// Initialize when API is ready
setTimeout(() => {
if (window.DirectualFilter) {
console.log('🚀 Custom filter ready!');
console.log('Available fields:', window.DirectualFilter.props.fields);
// Show current filter if any
const current = window.DirectualFilter.props.currentFilter;
if (current) {
updateFilterStatus(current);
}
}
}, 100);
</script>
```
This example creates a comprehensive product search interface with:
- Text search for product names
- Numeric range filtering for prices
- Dropdown category selection
- **Sorting by multiple fields with direction control**
- Combined filter logic with AND operators
- Clear visual feedback with filter/sort status
- Keyboard shortcuts (Enter to search)
The filter generates DQL like: `'productName' like 'laptop' AND 'price' >= '100' AND 'price' <= '500' AND 'category' = 'electronics'`
With sorting like: `{field: 'price', direction: 'desc'}` for highest price first.
### API Usage Examples:
```javascript
// Filter only
window.DirectualFilter.emit("'name' like 'search'");
// Filter with sorting
window.DirectualFilter.emit("'name' like 'search'", {field: 'price', direction: 'asc'});
// Sorting only (keep current filter)
window.DirectualFilter.emit(window.DirectualFilter.props.currentFilter, {field: 'name', direction: 'desc'});
// Clear everything
window.DirectualFilter.emit('', null);
```Last updated
Was this helpful?