Query Filter Loading Fix - Implementation
Problem Identified
From the diagnostic logs, the issue was NOT that query data wasn't being passed - it WAS being passed correctly. The problems were:
- Alpine Component Registration Failure -
queryBuilderEdit is not definederror - Incorrect Condition Logic - Checking if string equals literal template syntax
{{ query_json|escapejs }} - Timing Issue - Alpine.data() being registered AFTER HTMX inserted the DOM and Alpine scanned for x-data attributes
Root Cause
Looking at the console output:
Query JSON String from template: {"condition": "AND", "primary_model": "user", ...}
Query JSON is not available in context. Starting with empty groups.
The JSON WAS successfully rendered by Django templating, but the condition checking if queryJsonString === '{{ query_json|escapejs }}' was incorrect - this literal syntax would never match after templating.
Solution Implemented
1. Pre-Parse Template Data (Lines 20-47)
Instead of relying on parsing template variables inside Alpine methods, create a global QUERY_DATA object at the top level:
const QUERY_DATA = {
queryId: parseInt('{{ object.id }}'),
queryName: `{{ object.name }}`,
selectedModel: `{{ object.content_type.model }}`,
filtersByModel: {},
queryJson: null
};
try {
QUERY_DATA.filtersByModel = JSON.parse('{{ filters_by_model_json|escapejs }}');
} catch (e) {
console.error('[SETUP] Error parsing filters_by_model_json:', e);
}
try {
const queryJsonString = '{{ query_json|escapejs }}';
if (queryJsonString && queryJsonString.trim().length > 0) {
QUERY_DATA.queryJson = JSON.parse(queryJsonString);
}
} catch (e) {
console.error('[SETUP] Error parsing query_json:', e);
}
Benefits: - ✅ Parsing happens immediately when script loads, before Alpine processes DOM - ✅ All template variables are available to Alpine data object - ✅ Proper error handling with try/catch - ✅ No need to check for placeholder strings in methods
2. Updated Alpine Data Initialization (Lines 65-75)
Changed from inline template parsing to using pre-parsed global data:
window.Alpine.data('queryBuilderEdit', () => ({
queryId: QUERY_DATA.queryId,
queryName: QUERY_DATA.queryName,
selectedModel: QUERY_DATA.selectedModel,
filtersByModel: QUERY_DATA.filtersByModel,
// ... rest of properties
}));
3. Simplified loadQueryData() Method (Lines 104-153)
Removed template variable parsing and incorrect condition checks:
loadQueryData() {
// Load filters for the selected model
if (this.selectedModel && this.filtersByModel[this.selectedModel]) {
// ... load filters
}
// Use pre-parsed query data
try {
if (!QUERY_DATA.queryJson) {
console.warn('[loadQueryData] No query data available...');
if (this.groups.length === 0) {
this.addGroup();
}
return;
}
const queryData = QUERY_DATA.queryJson;
this.originalQueryData = JSON.parse(JSON.stringify(queryData)); // Deep copy
if (queryData && queryData.groups && queryData.groups.length > 0) {
// Reconstruct groups and rules
this.groups = queryData.groups.map(group => ({
id: Date.now() + Math.random(),
condition: group.condition || 'AND',
rules: group.rules.map(rule => ({
id: Date.now() + Math.random(),
field: rule.field,
operator: rule.operator,
value: Array.isArray(rule.value) ? rule.value[0] : rule.value,
value2: Array.isArray(rule.value) ? rule.value[1] : ''
}))
}));
console.log('[loadQueryData] Loaded', this.groups.length, 'groups...');
} else {
if (this.groups.length === 0) {
this.addGroup();
}
}
} catch (error) {
console.error('[loadQueryData] Error:', error);
if (this.groups.length === 0) {
this.addGroup();
}
}
}
4. Fixed Alpine Initialization (Lines 356-385)
Improved the initialization sequence:
// For fresh page loads where Alpine is already loaded
if (window.Alpine && window.Alpine.data) {
console.log('[Init] Alpine already loaded, initializing now');
initializeEditQueryBuilder();
}
// For HTMX-loaded partials
document.addEventListener('htmx:afterSettle', () => {
console.log('[htmx:afterSettle] Event fired, initializing edit query builder');
setTimeout(() => {
initializeEditQueryBuilder();
}, 100); // Small delay to ensure Alpine is fully ready
});
// Fallback for DOMContentLoaded
document.addEventListener('DOMContentLoaded', () => {
if (!window.Alpine) {
console.log('[DOMContentLoaded] Alpine not yet available...');
return;
}
console.log('[DOMContentLoaded] Initializing edit query builder');
initializeEditQueryBuilder();
});
Benefits: - ✅ Handles both fresh page loads and HTMX-loaded partials - ✅ Proper Alpine availability checking - ✅ Small timeout for HTMX to ensure DOM is settled - ✅ Better error messages with prefixes for debugging
Expected Behavior After Fix
When clicking the Edit button on a saved query:
- Server side: Django view passes
query_jsoncontaining saved filters - Template execution: Django renders template variables
- Script execution: - QUERY_DATA object created and populated - JSON parsed and stored
- HTMX loads partial: htmx:afterSettle fires
- Alpine initialization:
initializeEditQueryBuilder()registers component - Alpine processing: x-data="queryBuilderEdit" component initializes with data
- Init callback:
init()method callsloadQueryData() - Groups loaded: Saved query groups and rules display in the UI
Browser Console Output
Expected logs (in order):
[SETUP] Filters by Model loaded: (2) ['user', 'entity']
[SETUP] Query JSON loaded: {condition: "AND", primary_model: "user", ...}
[Init] Setting up event listeners for Alpine initialization
[htmx:afterSettle] Event fired, initializing edit query builder
=== Initializing Edit Query Builder ===
Query ID: 1
Query Name: test query
Selected Model: user
Has Query JSON: true
[Alpine] Initializing tree for element: <div x-data="queryBuilderEdit">
[loadQueryData] Loaded filters for model: user
[loadQueryData] Loaded 1 groups from saved query: [{...}]
Files Modified
eneza_workflow_engine/templates/saved_query/partials/edit_query_builder_partial.html- Added pre-parsing of template variables - Fixed Alpine data initialization - Improved loadQueryData() logic - Enhanced event listener setup
Testing Steps
- Navigate to a saved query detail page
- Click the "Edit" button
- Open DevTools Console (F12)
- Check that logs appear in order without errors
- Verify that saved query conditions appear in the query builder UI
- Test editing and updating the query
Debugging
If the fix doesn't work, check:
- Console logs - Verify data is being pre-parsed
- Network tab - Confirm HTMX request contains rendered HTML
- Alpine errors - Should show proper component initialization
- Query builder UI - Should display saved groups and rules visually