Fix search issues: pagination, input clearing, and minimum character requirement
This commit is contained in:
parent
0f23b29078
commit
92862e682a
|
|
@ -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
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue