我正在使用 vanilla JavaScript 开发动态表过滤功能,其中我使用下拉菜单来过滤表中显示的数据。每个下拉列表都有一个默认选项(带有空字符串值)和与数据列相对应的其他几个选项。我的问题是,在选择不同的选项后,重新选择默认选项时,更改事件似乎不会触发。这可以防止表重置为其原始的、未过滤的状态。
这是我的下拉 HTML 在进行选择之前和之后的简化版本:
<th>
<select id="filter-findingStatus" class="filter-dropdown" data-columnname="findingStatus">
<option value="">All findingStatus</option>
<option value="in_progress">in_progress</option>
<option value="false_positive">false_positive</option>
<option value="closed">closed</option>
<option value="ignored">ignored</option>
<option value="new">new</option>
</select>
做出选择后:
<th>
<select id="filter-findingStatus" class="filter-dropdown" data-columnname="findingStatus">
<option value="">All findingStatus</option>
<option value="ignored">ignored</option>
</select>
</th>
这是 JavaScript 部分,我在其中监听更改事件并尝试过滤表:它是构造函数表类的一部分。
class Table {
constructor(tableId, headers) {
this.tableId = tableId;
this.headers = headers;
this.uniqueValues = {};
this.currentFilters = {};
this.originalData = [];
this.loadedData = [];
this.currentlyLoadedCount = 0;
this.loadIncrement = 20;
console.info(`Table ID: ${this.tableId}`);
const tableIdElement = document.getElementById(tableId);
// Check if the table element exists
if (!tableIdElement) {
console.error(`Table not found for tableId: ${tableId}`);
return;
}
if (tableIdElement) {
const scrollContainer = tableIdElement.closest('.table-scroll-container');
if (scrollContainer) {
scrollContainer.addEventListener('scroll', () => {
if ((scrollContainer.offsetHeight + scrollContainer.scrollTop) >= scrollContainer.scrollHeight) {
this.loadMoreRows();
}
});
} else {
console.error(`Scroll container not found for table with id: ${this.tableId}`);
}
} else {
console.error(`Table with id: ${this.tableId} not found`);
}
const dataBody = document.getElementById(this.tableId).querySelector('tbody');
if (!dataBody) {
console.error(`Table body not found for ID: ${this.tableId}`);
}
dataBody.innerHTML = '';
// Get all filter dropdowns
const filterDropdowns = document.querySelectorAll('.filter-dropdown');
filterDropdowns.forEach(dropdown => {
console.log(`Adding event listener to dropdown with column name: ${dropdown.dataset.columnname}`);
dropdown.addEventListener('change', (event) => {
console.log('Dropdown change event triggered', event);
// Get the selected value
const selectedValue = event.target.value;
// Get the column name from the dropdown's data-columnName attribute
const columnName = dropdown.dataset.columnname;
// Call the filterTables method with the column name and selected value
this.filterTables(columnName, selectedValue);
});
});
}
我的过滤表方法:
filterTables(columnName, selectedValue) {
console.log(`Filtering tables for column: ${columnName}, selected value: ${selectedValue}`);
// If the selected value is the default value, remove the filter for this column
if (selectedValue === '') {
console.log(`Default (empty) value selected for column: ${columnName}. Removing filter for this column.`);
delete this.currentFilters[columnName];
// Reset the loadedData to the originalData
this.loadedData = [...this.originalData];
} else {
// Otherwise, update the current filters
console.log(`Non-default value selected for column: ${columnName}. Updating filter for this column.`);
this.currentFilters[columnName] = selectedValue;
}
console.log(`Current filters:`, this.currentFilters);
// Update the dropdown to show the currently selected value
const dropdown = document.querySelector(`.filter-dropdown[data-columnName="${columnName}"]`);
if (dropdown) {
dropdown.value = selectedValue;
}
// Apply all filters to the originalData array
this.loadedData = this.originalData.filter(item => {
for (let column in this.currentFilters) {
const cellValue = item[column] || '';
const filterValue = this.currentFilters[column];
if (filterValue !== '' && !cellValue.includes(filterValue)) {
return false; // Exclude this item if it doesn't match the filter
}
}
return true; // Include this item if it matches all filters
});
console.log(`Loaded data after applying filters:`, this.loadedData);
// Clear the table
const dataBody = document.getElementById(this.tableId).querySelector('tbody');
dataBody.innerHTML = '';
// Reset the currentlyLoadedCount
this.currentlyLoadedCount = 0;
// Load the first batch of rows
this.loadMoreRows();
// Store the unique filter options based on the currently filtered data
this.storeAllUniqueFilterOptions(this.loadedData);
}
这两种方法是我获取下拉选项并附加它们的方法:
storeAllUniqueFilterOptions(data) {
// Reset the uniqueValues object
this.uniqueValues = {};
data.forEach(item => {
this.headers.forEach(header => {
const cellValue = item[header] || '';
if (!this.uniqueValues[header]) {
this.uniqueValues[header] = new Set();
}
this.uniqueValues[header].add(cellValue);
});
});
this.populateFilterDropdowns();
}
populateFilterDropdowns() {
for (const [key, valueSet] of Object.entries(this.uniqueValues)) {
const dropdown = document.querySelector(`.filter-dropdown[data-columnName="${key}"]`);
if (dropdown) {
// Preserve the default option so it can be re-added after clearing
const defaultOption = dropdown.querySelector('option[value=""]');
// Clear old options
dropdown.innerHTML = '';
// Re-append the default option
if (defaultOption) {
dropdown.appendChild(defaultOption.cloneNode(true)); // Append a cloned node of the default option
}
// Populate filter dropdowns with unique values
valueSet.forEach(value => {
const option = document.createElement('option');
option.value = value;
option.textContent = value;
dropdown.appendChild(option);
});
}
}
}
但是,当我选择默认选项时,不会触发任何日志,包括更改事件内的日志。这意味着在这种情况下该事件不会触发,尽管它对于所有其他选项都可以正常工作。此行为会阻止数据按预期重置。
我尝试过的:
验证事件监听器是否正确附加到所有其他选项 在控制台中检查 JavaScript 错误(未发现)。 选择默认选项时手动触发事件(不理想并且无法使其按预期工作)。
我的问题:即使重新选择默认选项,如何确保更改事件触发,以便我的表可以重置为其原始的、未过滤的状态?
任何见解或建议将不胜感激!
能够找到解决方案,即使在应用过滤器后,默认值仍保持选中状态,使其不可选择。所以我只需要在填充 filterDropdowns 结束时重置之前选择的值。
populateFilterDropdowns() {
for (const [key, valueSet] of Object.entries(this.uniqueValues)) {
const dropdown = document.querySelector(`.filter-dropdown[data-columnName="${key}"]`);
if (dropdown) {
// Remember the currently selected value
const selectedValue = dropdown.value;
// Preserve the default option so it can be re-added after clearing
// Clear old options
dropdown.innerHTML = '';
// Create and append the default option
this.createDefaultOption(dropdown, key);
// Populate filter dropdowns with unique values
valueSet.forEach(value => {
const option = document.createElement('option');
option.value = value;
option.textContent = value;
dropdown.appendChild(option);
});
// Reselect the previously selected value
dropdown.value = selectedValue;
}
}
}