Skip to content

Instantly share code, notes, and snippets.

@jotraverso
Last active May 8, 2022 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jotraverso/124e46ddd8a5caa0bc5a3b5bdc18adc0 to your computer and use it in GitHub Desktop.
Save jotraverso/124e46ddd8a5caa0bc5a3b5bdc18adc0 to your computer and use it in GitHub Desktop.
LWC autocomplete combobox
<template>
<div class="slds-form-element">
<label class="slds-form-element__label" for="combobox-id-16" id="combobox-label-id-138"><template
if:true={required}>
<abbr class="slds-required" title="required">* </abbr>
</template>{label}</label>
<div class="slds-form-element__control">
<div class="slds-combobox_container">
<div class="slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open">
<div class="slds-combobox__form-element slds-input-has-icon slds-input-has-icon_right" role="none">
<input type="text" class="slds-input slds-combobox__input" id="combobox-id-16"
value={selectedLabel} aria-activedescendant="option1" aria-autocomplete="list"
aria-controls="listbox-id-12" aria-expanded="true" aria-haspopup="listbox"
required={required} autocomplete="off" role="combobox" placeholder="Search..."
onkeyup={handleChangeSearchTerm} onfocus={handleFocus} onblur={handleBlur} />
<span
class="slds-icon_container slds-icon-utility-search slds-input__icon slds-input__icon_right">
<svg class="slds-icon slds-icon slds-icon_x-small slds-icon-text-default"
aria-hidden="true">
<use xlink:href="/_slds/icons/utility-sprite/svg/symbols.svg#search"></use>
</svg>
</span>
</div>
<template if:true={showOptions}>
<div id="listbox-id-12" class="slds-dropdown slds-dropdown_length-5 slds-dropdown_fluid"
role="listbox">
<ul class="slds-listbox slds-listbox_vertical" role="presentation">
<template for:each={filteredOptions} for:item="option">
<li key={option.value} role="presentation" class="slds-listbox__item"
onclick={handleSelect} data-rowid={option.value} data-rowlabel={option.label}>
<div aria-selected="true"
class="slds-media slds-listbox__option slds-listbox__option_plain slds-media_small"
role="option">
<span class="slds-media__figure slds-listbox__option-icon"></span>
<span class="slds-media__body">
<span class="slds-truncate"
title="Burlington Textiles Corp of America">{option.label}</span>
</span>
</div>
</li>
</template>
</ul>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
/* eslint-disable @lwc/lwc/no-async-operation */
import { api, LightningElement } from "lwc";
export default class AutocompleteCombobox extends LightningElement {
@api label;
@api required;
@api placeholder;
@api options;
filteredOptions = [];
toggleOptions = false;
selectedValue;
selectedLabel;
handleFocus() {
this.toggleOptions = true;
}
handleBlur() {
const cmp = this;
setTimeout(function () {
cmp.toggleOptions = false;
// if the selected label is empty must trigger the change event
if (cmp.selectedLabel === "") {
cmp.selectedValue = "";
cmp.dispatchEvent(new CustomEvent("change", { bubbles: false, detail: { value: "", target: cmp.name } }));
}
}, 200);
}
handleSelect(event) {
let selectedValue = event.currentTarget.dataset.rowid;
let selectedLabel = event.currentTarget.dataset.rowlabel;
this.selectedValue = selectedValue;
this.selectedLabel = selectedLabel;
this.toggleOptions = false;
this.dispatchEvent(new CustomEvent("change", { bubbles: false, detail: { value: this.selectedValue, target: this.name } }));
}
handleChangeSearchTerm(event) {
clearTimeout(this.searchTO);
const searchTerm = event.target.value;
const cmp = this;
this.selectedLabel = searchTerm;
this.selectedValue = "";
this.searchTO = setTimeout(() => {
cmp.filteredOptions = cmp.options.filter((option) => cmp.selectedLabel === "" || option.label.toLowerCase().includes(searchTerm.toLowerCase()));
}, 400);
this.toggleOptions = true;
}
connectedCallback() {
this.filteredOptions = this.options?.slice(0) ?? [];
this.selectedLabel = "";
this.selectedValue = "";
}
get showOptions() {
if (this.selectedLabel === "") {
this.filteredOptions = this.options?.slice(0);
}
return this.toggleOptions && this.filteredOptions?.length > 0;
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>54.0</apiVersion>
<isExposed>false</isExposed>
<description>Autocomplete Combobox</description>
</LightningComponentBundle>
<template>
<lightning-card>
<div class="slds-p-around_medium" style="width: 800px;">
<label>Selected Contact Id: {contactId}</label>
<c-autocomplete-combobox options={options} onchange={handleChange} label="Select a contact"
placeholder="Search...">
</c-autocomplete-combobox>
<lightning-card if:true={showContact} title={contactName} icon-name="standard:contact">
<lightning-record-form record-id={contactId} layout-type="Compact" object-api-name={sobjectName}
mode="readonly" columns="2">
</lightning-record-form>
</lightning-card>
</div>
</lightning-card>
</template>
import { LightningElement, wire } from "lwc";
import { getRecord, getFieldValue } from "lightning/uiRecordApi";
import getContacts from "@salesforce/apex/MyAppController.getContacts";
import CONTACT_NAME from "@salesforce/schema/Contact.Name";
import CONTACT_PHONE from "@salesforce/schema/Contact.Phone";
import SOBJECT_CONTACT from "@salesforce/schema/Contact";
export default class MyApp extends LightningElement {
@wire(getContacts)
contacts;
fileds = [CONTACT_NAME, CONTACT_PHONE];
@wire(getRecord, { recordId: "$contactId", fields: [CONTACT_NAME, CONTACT_PHONE] })
selectedContact;
contactId;
sobjectName = SOBJECT_CONTACT;
get options() {
return this.contacts?.data?.map((contact) => {
return { value: contact.Id, label: contact.Name };
});
}
handleChange(event) {
this.contactId = event.detail.value;
}
get showContact() {
return this.contactId ? true : false;
}
get contactName() {
return getFieldValue(this.selectedContact.data, CONTACT_NAME);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment