Fix search issues: pagination, input clearing, and minimum character requirement

This commit is contained in:
Mohamed Eltayar 2025-08-29 18:09:34 +03:00
parent 0f23b29078
commit 92862e682a
1 changed files with 156 additions and 143 deletions

View File

@ -51,7 +51,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
active: false,
originalData: null,
originalDomain: null,
filteredIds: null
filteredIds: null,
isSearching: false // Flag to prevent input clearing
};
},
@ -73,6 +74,11 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Store value
this._search.value = value;
// Require at least 2 characters or empty to search
if (value.length === 1) {
return; // Don't search for single character
}
// Debounce search
this._search.timer = setTimeout(function() {
self._performSearch(value);
@ -117,6 +123,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this._search.originalDomain = this.state.domain || [];
}
// Set searching flag
this._search.isSearching = true;
// Start search
this._search.active = true;
this._showLoading(true);
@ -132,14 +141,16 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Get fields to read
var fields = this._getReadFields();
// Execute search
// Execute search with pagination
var limit = this.state.limit || 80; // Use current page limit
this._rpc({
model: this.state.model,
method: 'search_read',
args: [domain],
kwargs: {
fields: fields,
limit: false,
limit: false, // Get all records for count
context: this.state.context || {}
}
}).then(function(results) {
@ -149,7 +160,10 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
self._clientSideSearch(value);
}).finally(function() {
self._search.active = false;
self._search.isSearching = false;
self._showLoading(false);
// Restore search value after search completes
self._restoreSearchInput();
});
},
@ -267,7 +281,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
var self = this;
var count = records.length;
// Show count
// Show count - KEEP IT VISIBLE
this.$('.oe_search_count').text(_t('Found: ') + count + _t(' records')).show();
if (count === 0) {
@ -278,43 +292,50 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// 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;
this.state.res_ids = this._search.filteredIds;
}
// Re-render the list body using the best method for Odoo 14
this._renderFilteredRecords(records);
// Re-render the list with pagination
this._renderFilteredRecordsWithPagination(records);
},
/**
* Render filtered records - Professional Odoo 14 compatible solution
* Render filtered records with proper pagination
*/
_renderFilteredRecords: function(records) {
_renderFilteredRecordsWithPagination: function(records) {
var self = this;
// Method 1: Try to trigger reload with filtered domain (Best for Odoo 14)
// Get current limit (default 80)
var limit = this.state.limit || 80;
var offset = 0;
// Get IDs for filtered records
var filteredIds = records.map(function(r) { return r.id; });
// Create domain to filter by IDs
var idDomain = [['id', 'in', filteredIds]];
// Try to use parent's reload method with proper pagination
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
// Update state temporarily
var originalDomain = this.state.domain;
this.state.domain = idDomain;
// Trigger parent reload with filtered domain
// Store total count for pagination
this.state.count = records.length;
// Reload with pagination settings
this.getParent().reload({
domain: idDomain,
context: this.state.context,
limit: false,
offset: 0
limit: limit, // Keep original pagination limit
offset: offset
}).then(function() {
self._afterRender();
// Restore search input and count
self._restoreSearchInput();
self.$('.oe_search_count').text(_t('Found: ') + records.length + _t(' records')).show();
}).catch(function(err) {
console.warn('Parent reload failed, trying alternative method:', err);
self._renderRecordsAlternative(records);
console.warn('Parent reload failed:', err);
// Fallback method
self._renderRecordsWithPagination(records, limit, offset);
});
return;
@ -323,67 +344,63 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
}
}
// Method 2: Try direct _renderBody if available
self._renderRecordsAlternative(records);
// Fallback: render with pagination
this._renderRecordsWithPagination(records, limit, offset);
},
/**
* Alternative render method for filtered records
* Render records with pagination (fallback)
*/
_renderRecordsAlternative: function(records) {
_renderRecordsWithPagination: function(records, limit, offset) {
var self = this;
// Try _renderBody if available
// Get records for current page
var pageRecords = records.slice(offset, offset + limit);
// Update state
if (this.state && this.state.data) {
this.state.data.records = pageRecords;
this.state.count = records.length; // Total count
this.state.res_ids = pageRecords.map(function(r) { return r.id; });
}
// Try to render using _renderBody
if (typeof this._renderBody === 'function') {
try {
// 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
// Remove existing rows
this.$('tbody .o_data_row').remove();
this.$('.oe_no_results').remove();
// Call render
// Render new rows
var result = this._renderBody();
// Handle promise
if (result && result.then) {
result.then(function() {
self._afterRender();
self._highlightSearchResults();
}).catch(function(err) {
console.error('_renderBody failed:', err);
self._fallbackRender(records);
self._restoreSearchInput();
self.$('.oe_search_count').text(_t('Found: ') + records.length + _t(' records')).show();
});
} else {
self._afterRender();
self._highlightSearchResults();
self._restoreSearchInput();
self.$('.oe_search_count').text(_t('Found: ') + records.length + _t(' records')).show();
}
return;
} catch (err) {
console.error('Alternative render error:', err);
console.error('Render error:', err);
this._fallbackRender(pageRecords);
}
} else {
this._fallbackRender(pageRecords);
}
// Final fallback to DOM manipulation
this._fallbackRender(records);
},
/**
* Highlight search results (optional visual enhancement)
* Restore search input value
*/
_highlightSearchResults: function() {
// Add subtle highlight to filtered rows
this.$('.o_data_row').addClass('oe_search_filtered');
_restoreSearchInput: function() {
// Don't restore if we're clearing
if (this._search && this._search.value && !this._search.isClearing) {
this.$('.oe_search_input').val(this._search.value);
this.$('.oe_clear_search').show();
}
},
/**
@ -397,63 +414,39 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
var $rows = this.$('.o_data_row');
if ($rows.length === 0) {
// 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');
console.warn('No data rows found in DOM');
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;
// Show matching rows (limited to page size)
var shown = 0;
var limit = this.state.limit || 80;
$rows.each(function() {
if (shown >= limit) return false; // Stop if reached limit
var $row = $(this);
var rowId = self._getRowId($row);
if (rowId && recordIds.includes(rowId)) {
$row.show();
visibleCount++;
shown++;
}
});
// Show message if no visible rows
if (visibleCount === 0) {
if (shown === 0) {
this._showNoResults();
}
this._afterRender();
this._restoreSearchInput();
},
/**
* Get row ID from DOM element - Enhanced version
* Get row ID from DOM element
*/
_getRowId: function($row) {
// Method 1: data-id attribute
@ -480,32 +473,14 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
if (idText && !isNaN(idText)) return parseInt(idText);
}
// Method 5: Extract from class or other attributes
// Method 5: Extract from class
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);
}
return null;
},
/**
* After render tasks
*/
_afterRender: function() {
// Restore search value
if (this._search && this._search.value) {
this.$('.oe_search_input').val(this._search.value);
this.$('.oe_clear_search').show();
}
},
/**
* Client-side search fallback
*/
@ -513,8 +488,14 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
var searchLower = value.toLowerCase();
var normalized = this._normalizeArabic(searchLower);
var visible = 0;
var limit = this.state.limit || 80;
this.$('.o_data_row').each(function() {
if (visible >= limit) {
$(this).hide();
return true; // Continue but hide excess rows
}
var $row = $(this);
var text = $row.text().toLowerCase();
var match = text.includes(searchLower) || text.includes(normalized);
@ -523,21 +504,26 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
if (match) visible++;
});
// Update count
// Update count - KEEP VISIBLE
var msg = visible > 0 ?
_t('Showing: ') + visible + _t(' visible records') :
_t('Found: ') + visible + _t(' records') :
_t('No records found');
this.$('.oe_search_count').text(msg).show();
if (visible === 0) {
this._showNoResults();
}
this._restoreSearchInput();
},
/**
* Clear search and restore original view
*/
_clearSearch: function() {
// Set clearing flag
this._search.isClearing = true;
// Clear UI
this.$('.oe_search_input').val('');
this.$('.oe_clear_search').hide();
@ -553,16 +539,21 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this.state.domain = this._search.originalDomain;
}
// Restore original data
// Restore original data with proper pagination
if (this._search.originalData) {
this._restoreOriginalData();
this._restoreOriginalDataWithPagination();
} else {
// Just show all rows
this.$('.o_data_row').show();
// Just show all rows respecting pagination
var $rows = this.$('.o_data_row');
var limit = this.state.limit || 80;
$rows.each(function(index) {
$(this).toggle(index < limit);
});
}
// Remove highlight class
this.$('.o_data_row').removeClass('oe_search_filtered');
// Remove clearing flag
this._search.isClearing = false;
},
/**
@ -575,15 +566,16 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this.state.data.records.slice() : [],
count: this.state.count || 0,
res_ids: this.state.res_ids ? this.state.res_ids.slice() : [],
limit: this.state.limit
limit: this.state.limit,
offset: this.state.offset || 0
};
}
},
/**
* Restore original data
* Restore original data with pagination
*/
_restoreOriginalData: function() {
_restoreOriginalDataWithPagination: function() {
if (!this._search.originalData) return;
var self = this;
@ -591,31 +583,54 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Restore state
if (this.state) {
if (this.state.data) {
this.state.data.records = orig.records;
}
this.state.count = orig.count;
this.state.res_ids = orig.res_ids;
this.state.limit = orig.limit;
this.state.domain = this._search.originalDomain || [];
this.state.count = orig.count;
this.state.limit = orig.limit;
this.state.offset = orig.offset;
}
// Try parent reload first for clean restore
// Try parent reload 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
offset: orig.offset
}).then(function() {
self._afterRender();
// Clear search data
self._search.originalData = null;
self._search.originalDomain = null;
}).catch(function() {
// Fallback to direct render
self._renderRecordsAlternative(orig.records);
// Fallback
self._restoreOriginalRecords(orig);
});
} else {
// Direct render
this._renderRecordsAlternative(orig.records);
this._restoreOriginalRecords(orig);
}
},
/**
* Restore original records (fallback)
*/
_restoreOriginalRecords: function(orig) {
// Update state
if (this.state && this.state.data) {
this.state.data.records = orig.records;
this.state.count = orig.count;
this.state.res_ids = orig.res_ids;
}
// Re-render
if (typeof this._renderBody === 'function') {
this._renderBody();
} else {
// Show original rows with pagination
var $rows = this.$('.o_data_row');
var limit = orig.limit || 80;
$rows.each(function(index) {
$(this).toggle(index < limit);
});
}
// Clear stored data
@ -628,9 +643,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
*/
_showLoading: function(show) {
this.$('.oe_search_loading').toggle(show);
if (show) {
this.$('.oe_search_count').hide();
}
// Don't hide count when loading
},
/**