Et2Select: Fix selected search results sometimes disappeared

This commit is contained in:
nathan 2023-09-27 11:15:13 -06:00
parent 2d35529380
commit bbf676597f
2 changed files with 39 additions and 98 deletions

View File

@ -505,65 +505,6 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
}
}
/**
* Override this method from SlSelect to stick our own tags in there
*
syncItemsFromValue()
{
if(typeof super.syncItemsFromValue === "function")
{
super.syncItemsFromValue();
}
// Only applies to multiple
if(typeof this.displayTags !== "object" || !this.multiple)
{
return;
}
let overflow = null;
if(this.maxOptionsVisible > 0 && this.displayTags.length > this.maxOptionsVisible)
{
overflow = this.displayTags.pop();
}
const checkedItems = Object.values(this._menuItems).filter(item => this.value.includes(item.value));
this.displayTags = checkedItems.map(item => this._createTagNode(item));
if(checkedItems.length !== this.value.length && this.multiple)
{
// There's a value that does not have a menu item, probably invalid.
// Add it as a marked tag so it can be corrected or removed.
const filteredValues = this.value.filter(str => !checkedItems.some(obj => obj.value === str));
for(let i = 0; i < filteredValues.length; i++)
{
const badTag = this._createTagNode({
value: filteredValues[i],
getTextLabel: () => filteredValues[i],
classList: {value: ""}
});
badTag.variant = "danger";
badTag.contactPlus = false;
// Put it in front so it shows
this.displayTags.unshift(badTag);
}
}
// Re-slice & add overflow tag
if(overflow)
{
this.displayTags = this.displayTags.slice(0, this.maxOptionsVisible);
this.displayTags.push(overflow);
}
else if(this.multiple && this.rows == 1 && this.readonly && this.value.length > 1)
{
// Maybe more tags than we can show, show the count
this.displayTags.push(html`
<sl-tag class="multiple_tag" size=${this.size}>${this.value.length}</sl-tag> `);
}
}
*/
/**
* Tag used for rendering tags when multiple=true
* Used for creating, finding & filtering options.
@ -616,6 +557,12 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
{
super.handleOptionClick(event);
// Only interested in option clicks, but handler is bound higher
if(event.target.tagName !== "SL-OPTION")
{
return;
}
if(this._close_on_select)
{
this.hide();
@ -878,6 +825,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
.maxOptionsVisible=${0}
.value=${value}
@sl-change=${this.handleValueChange}
@mouseup=${this.handleOptionClick}
>
${icon}
${this._emptyLabelTemplate()}

View File

@ -789,6 +789,24 @@ export const Et2WithSearchMixin = dedupeMixin(<T extends Constructor<LitElement>
event.preventDefault();
return false;
}
// Find and keep any selected remote entries
// Doing it here catches keypress changes too
this.select.querySelectorAll("[aria-selected=true].remote").forEach((node) =>
{
const value = node.value.replaceAll("___", " ");
if(!node.selected || this._selected_remote.some(o => o.value == value))
{
return;
}
const remote_option_index = this._remote_options.findIndex(o => o.value == value);
if(remote_option_index >= 0)
{
console.log("Keeping " + value, this._remote_options[remote_option_index]);
this._selected_remote.push(node.option);
this._remote_options.splice(remote_option_index, 1);
}
});
return true;
}
@ -827,11 +845,13 @@ export const Et2WithSearchMixin = dedupeMixin(<T extends Constructor<LitElement>
*/
handleOptionClick(event)
{
// Need to keep the remote option - only if selected
if(event.target.classList.contains("remote") && !this.select_options.find(o => o.value == event.target.value))
// Only interested in option clicks, but handler is bound higher
if(event.target.tagName !== "SL-OPTION")
{
this._selected_remote.push({...event.target.option});
return;
}
if(typeof super.handleOptionClick == "function")
super.handleOptionClick(event);
this.updateComplete.then(() =>
@ -841,25 +861,6 @@ export const Et2WithSearchMixin = dedupeMixin(<T extends Constructor<LitElement>
{
this._searchInputNode.focus();
this._searchInputNode.select();
// If we were overlapping, reset
if(this._activeControls.classList.contains("novalue"))
{
this._handleMenuShow();
this._handleAfterShow();
}
// Scroll the new tag into view
if(event.detail)
{
// Causes sidemenu (calendar) to scroll to top & get stuck
/*
this.updateComplete.then(() =>
{
this.shadowRoot.querySelector("et2-tag[value='" + event.detail.item.value.replace(/'/g, "\\\'") + "']")?.scrollIntoView({block: "nearest"});
});
*/
}
}
else if(!this.multiple && this.searchEnabled)
{
@ -1086,13 +1087,10 @@ export const Et2WithSearchMixin = dedupeMixin(<T extends Constructor<LitElement>
// Remove any previously selected remote options that aren't used anymore
this._selected_remote = this._selected_remote.filter((option) =>
{
return this.multiple ? this.value.indexOf(option.value) != -1 : this.value == option.value;
return this.multiple ? this.value.indexOf(<string>option.value) != -1 : this.value == option.value;
});
// Remove remote options that aren't used
let keepers = this._selected_remote.reduce((prev, current) =>
{
return prev + ":not([value='" + ('' + current.value).replace(/'/g, "\\\'") + "'])";
}, "");
this._remote_options = [];
// Not searching anymore, clear flag
this.select_options.map((o) => o.isMatch = null);
@ -1234,24 +1232,19 @@ export const Et2WithSearchMixin = dedupeMixin(<T extends Constructor<LitElement>
return Promise.resolve();
}
// Add a "remote" class so we can tell these apart from any local results
entries.forEach((entry) =>
for(let i = entries.length - 1; i >= 0; i--)
{
const entry = entries[i];
entry.class = (entry.class || "") + " remote";
// Server says it's a match
entry.isMatch = true;
});
// Add in remote options, avoiding duplicates
this.select_options.filter(function(item)
{
let i = entries.findIndex(x => (x.value == item.value));
if(i <= -1)
// Avoid duplicates with existing options
if(this.select_options.some(o => o.value == entry.value))
{
entries.push(item);
entries.splice(i, 1);
}
return null;
});
}
this._remote_options = entries;
this.requestUpdate("select_options");