Merge pull request #4418 from expsa/eltayar

Fix: General Search Tree View - List Rendering After Search
This commit is contained in:
Mohamed Eltayar 2025-08-29 17:48:28 +03:00 committed by GitHub
commit 0f23b29078
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 173 additions and 35 deletions

View File

@ -49,7 +49,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
timer: null,
value: '',
active: false,
originalData: null
originalData: null,
originalDomain: null,
filteredIds: null
};
},
@ -107,10 +109,13 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
return;
}
// Store original data on first search
// Store original data and domain on first search
if (!this._search.originalData) {
this._storeOriginalData();
}
if (!this._search.originalDomain) {
this._search.originalDomain = this.state.domain || [];
}
// Start search
this._search.active = true;
@ -120,8 +125,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
var domain = this._buildSearchDomain(value);
// Add base domain if exists
if (this.state.domain && this.state.domain.length > 0) {
domain = ['&'].concat(this.state.domain).concat(domain);
if (this._search.originalDomain && this._search.originalDomain.length > 0) {
domain = ['&'].concat(this._search.originalDomain).concat(domain);
}
// Get fields to read
@ -270,33 +275,83 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
return;
}
// Update state data
// Store filtered IDs for later use
this._search.filteredIds = records.map(function(r) { return r.id; });
// Update state data properly
if (this.state && this.state.data) {
this.state.data.records = records;
this.state.count = count;
// Update IDs list
this.state.res_ids = records.map(function(r) { return r.id; });
this.state.res_ids = this._search.filteredIds;
}
// Re-render the list body
this._renderRecords(records);
// Re-render the list body using the best method for Odoo 14
this._renderFilteredRecords(records);
},
/**
* Render records - The correct way for Odoo 14
* Render filtered records - Professional Odoo 14 compatible solution
*/
_renderRecords: function(records) {
_renderFilteredRecords: function(records) {
var self = this;
// Method 1: Use _renderBody if available
// Method 1: Try to trigger reload with filtered domain (Best for Odoo 14)
if (this.getParent() && typeof this.getParent().reload === 'function') {
try {
// Create domain to filter by IDs
var idDomain = [['id', 'in', this._search.filteredIds]];
// Update state domain temporarily
this.state.domain = idDomain;
// Trigger parent reload with filtered domain
this.getParent().reload({
domain: idDomain,
context: this.state.context,
limit: false,
offset: 0
}).then(function() {
self._afterRender();
}).catch(function(err) {
console.warn('Parent reload failed, trying alternative method:', err);
self._renderRecordsAlternative(records);
});
return;
} catch (err) {
console.warn('Reload method failed:', err);
}
}
// Method 2: Try direct _renderBody if available
self._renderRecordsAlternative(records);
},
/**
* Alternative render method for filtered records
*/
_renderRecordsAlternative: function(records) {
var self = this;
// Try _renderBody if available
if (typeof this._renderBody === 'function') {
try {
// Ensure state is ready
// Update state properly
if (this.state && this.state.data) {
// Store current state
var originalCount = this.state.count;
var originalLimit = this.state.limit;
// Update for filtered records
this.state.data.records = records;
this.state.count = records.length;
this.state.limit = false; // Show all filtered records
}
// Remove existing rows to force full re-render
this.$('tbody .o_data_row').remove();
this.$('.oe_no_results').remove();
// Call render
var result = this._renderBody();
@ -304,23 +359,33 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
if (result && result.then) {
result.then(function() {
self._afterRender();
self._highlightSearchResults();
}).catch(function(err) {
console.error('Render failed:', err);
console.error('_renderBody failed:', err);
self._fallbackRender(records);
});
} else {
self._afterRender();
self._highlightSearchResults();
}
return;
} catch (err) {
console.error('Render error:', err);
console.error('Alternative render error:', err);
}
}
// Fallback to DOM manipulation
// Final fallback to DOM manipulation
this._fallbackRender(records);
},
/**
* Highlight search results (optional visual enhancement)
*/
_highlightSearchResults: function() {
// Add subtle highlight to filtered rows
this.$('.o_data_row').addClass('oe_search_filtered');
},
/**
* Fallback render using DOM manipulation
*/
@ -332,26 +397,55 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
var $rows = this.$('.o_data_row');
if ($rows.length === 0) {
// No rows in DOM, can't filter
console.warn('No data rows found in DOM');
// Try to force re-render if no rows in DOM
if (this._search.originalData && this._search.originalData.records.length > 0) {
// Restore original data first
this.state.data.records = this._search.originalData.records;
// Try to render all rows
if (typeof this._renderBody === 'function') {
this._renderBody().then(function() {
// Now filter the rendered rows
setTimeout(function() {
self._filterDOMRows(recordIds);
}, 100);
});
return;
}
}
console.warn('No data rows found in DOM and cannot re-render');
return;
}
// Filter existing DOM rows
this._filterDOMRows(recordIds);
},
/**
* Filter DOM rows by IDs
*/
_filterDOMRows: function(recordIds) {
var self = this;
var $rows = this.$('.o_data_row');
// Hide all rows first
$rows.hide();
// Show matching rows
var visibleCount = 0;
$rows.each(function() {
var $row = $(this);
var rowId = self._getRowId($row);
if (rowId && recordIds.includes(rowId)) {
$row.show();
visibleCount++;
}
});
// Show message if no visible rows
if (this.$('.o_data_row:visible').length === 0) {
if (visibleCount === 0) {
this._showNoResults();
}
@ -359,31 +453,45 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
},
/**
* Get row ID from DOM element
* Get row ID from DOM element - Enhanced version
*/
_getRowId: function($row) {
// Try different methods to get ID
// Method 1: data-id attribute
var id = $row.data('id');
if (id) return parseInt(id);
// Method 2: Check for record object
var record = $row.data('record');
if (record && record.res_id) return record.res_id;
if (record) {
if (record.res_id) return record.res_id;
if (record.id) return record.id;
if (record.data && record.data.id) return record.data.id;
}
// Method 3: Look in first cell with field name
// Method 3: Look for Odoo's internal data
if ($row[0] && $row[0].dataset) {
if ($row[0].dataset.id) return parseInt($row[0].dataset.id);
}
// Method 4: Check first cell for ID field
var $idCell = $row.find('td[data-field="id"]');
if ($idCell.length) {
var idText = $idCell.text().trim();
if (idText && !isNaN(idText)) return parseInt(idText);
}
// Method 5: Extract from class or other attributes
var classes = $row.attr('class') || '';
var match = classes.match(/o_data_row_(\d+)/);
if (match) return parseInt(match[1]);
// Method 6: Try to find ID in any cell text that looks like an ID
var $firstCell = $row.find('td.o_data_cell:first');
if ($firstCell.length) {
var cellData = $firstCell.data();
if (cellData && cellData.id) return parseInt(cellData.id);
}
// Method 4: Extract from class or other attributes
var classes = $row.attr('class') || '';
var match = classes.match(/o_data_row_(\d+)/);
if (match) return parseInt(match[1]);
return null;
},
@ -394,6 +502,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Restore search value
if (this._search && this._search.value) {
this.$('.oe_search_input').val(this._search.value);
this.$('.oe_clear_search').show();
}
},
@ -426,7 +535,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
},
/**
* Clear search
* Clear search and restore original view
*/
_clearSearch: function() {
// Clear UI
@ -437,6 +546,12 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Clear state
this._search.value = '';
this._search.filteredIds = null;
// Restore original domain
if (this._search.originalDomain !== null) {
this.state.domain = this._search.originalDomain;
}
// Restore original data
if (this._search.originalData) {
@ -445,6 +560,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Just show all rows
this.$('.o_data_row').show();
}
// Remove highlight class
this.$('.o_data_row').removeClass('oe_search_filtered');
},
/**
@ -456,7 +574,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
records: this.state.data && this.state.data.records ?
this.state.data.records.slice() : [],
count: this.state.count || 0,
res_ids: this.state.res_ids ? this.state.res_ids.slice() : []
res_ids: this.state.res_ids ? this.state.res_ids.slice() : [],
limit: this.state.limit
};
}
},
@ -467,6 +586,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
_restoreOriginalData: function() {
if (!this._search.originalData) return;
var self = this;
var orig = this._search.originalData;
// Restore state
@ -476,13 +596,31 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
}
this.state.count = orig.count;
this.state.res_ids = orig.res_ids;
this.state.limit = orig.limit;
this.state.domain = this._search.originalDomain || [];
}
// Re-render
this._renderRecords(orig.records);
// Try parent reload first for clean restore
if (this.getParent() && typeof this.getParent().reload === 'function') {
this.getParent().reload({
domain: this._search.originalDomain || [],
context: this.state.context,
limit: orig.limit,
offset: 0
}).then(function() {
self._afterRender();
}).catch(function() {
// Fallback to direct render
self._renderRecordsAlternative(orig.records);
});
} else {
// Direct render
this._renderRecordsAlternative(orig.records);
}
// Clear stored data
this._search.originalData = null;
this._search.originalDomain = null;
},
/**
@ -517,7 +655,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
},
/**
* Normalize Arabic text
* Normalize Arabic text for better search
*/
_normalizeArabic: function(text) {
if (!text) return '';