파스타집
Multi-Select Quick Search Component 본문
customSearch.html
<template>
<lightning-card title="Custom Search" icon-name="utility:search">
<div class="slds-p-horizontal_small">
<div class="search-container">
<lightning-input type="search" label="Search" onchange={searchItems} onfocus={showItems} onfocusout={hideItems} placeholder="Search..."></lightning-input>
<div class="slds-tabs_card slds-float_left slds-hide">
<ul>
<template for:each={dataList} for:item="data">
<li class="slds-truncate" key={data.value} onmousedown={selectItem} data-value={data.value}>{data.label}</li>
</template>
</ul>
</div>
<template for:each={selectedDataList} for:item="selectedData">
<lightning-pill key={selectedData.value} label={selectedData.label} data-value={selectedData.value} onremove={removeItem}></lightning-pill>
</template>
</div>
</div>
</lightning-card>
</template>
customSearch.js
import {LightningElement, track} from 'lwc';
const SLDS_HIDE = 'slds-hide';
const SELECTED = 'selected';
export default class CustomSearch extends LightningElement {
@track dataList = [
{label: 'GenePoint', value: '0015h000015pZvtAAE'},
{label: 'United Oil & Gas, UK', value: '0015h000015pZvrAAE'},
{label: 'United Oil & Gas, Singapore', value: '0015h000015pZvsAAE'},
{label: 'Edge Communications', value: '0015h000015pZvjAAE'},
{label: 'Burlington Textiles Corp of America', value: '0015h000015pZvkAAE'},
{label: 'Pyramid Construction Inc.', value: '0015h000015pZvlAAE'},
{label: 'Dickenson plc', value: '0015h000015pZvmAAE'},
{label: 'Grand Hotels & Resorts Ltd', value: '0015h000015pZvnAAE'},
{label: 'Express Logistics and Transport', value: '0015h000015pZvpAAE'},
{label: 'University of Arizona', value: '0015h000015pZvqAAE'},
{label: 'United Oil & Gas Corp.', value: '0015h000015pZvoAAE'},
{label: 'sForce', value: '0015h000015pZvuAAE'},
{label: '권리에 대한 샘플 계정', value: '0015h0000142yc3AAA'}
];
@track selectedDataList = [];
get tabCard() {
return this.template.querySelector('.slds-tabs_card');
}
get allItems() {
return [...this.template.querySelectorAll('li')];
}
get visibleItems() {
return [...this.template.querySelectorAll(`li:not(.${SELECTED})`)];
}
searchItems({target: {value}}) {
if(value) {
this.visibleItems.forEach(item => item.innerText.toUpperCase().includes(value.toUpperCase()) ? item.classList.remove(SLDS_HIDE) : item.classList.add(SLDS_HIDE));
} else {
this.visibleItems.forEach(item => item.classList.remove(SLDS_HIDE));
}
}
showItems() {
this.tabCard.classList.remove(SLDS_HIDE);
}
hideItems() {
this.tabCard.classList.add(SLDS_HIDE);
}
selectItem({target: {dataset: {value}}}) {
this.visibleItems.find(item => item.dataset.value === value).classList.add(SELECTED);
this.selectedDataList.push(this.dataList.find(data => data.value === value));
this.hideItems();
}
removeItem({target: {dataset: {value}}}) {
this.selectedDataList = this.selectedDataList.filter(selectedData => selectedData.value !== value);
this.allItems.find(item => item.dataset.value === value).classList.remove(SELECTED);
}
}
customSearch.css
li {
padding: 6px
}
li:hover {
background-color: var(--lwc-colorBackgroundRowHover)
}
.slds-tabs_card {
position: absolute;
z-index: 1;
padding: 3px 0;
width: 100%;
max-height: 200px;
overflow: auto;
cursor: pointer
}
.selected {
display: none;
}
.search-container {
max-width: 500px;
position: relative
}
요구사항으로 정말 많이 나오는데 구현하기 귀찮은 컴포넌트 중 하나.
dataList를 받아온 후 selectedDataList를 반환하는 패턴이므로 입맛에 맞게 수정해서 사용하면 된다.
항목에 아이콘을 추가하거나 비동기 검색기능을 넣어도 괜찮을 것 같다.
컴포넌트 작동 원리
- Input에 focus가 발생하면 dropdown을 보여주고, focus가 빠지면 dropdown을 숨긴다.
- Quick Search를 하는 경우 검색 결과에 해당하지 않는 항목에 .slds-hide를 붙여서 일시적으로 숨긴다.
- 선택된 항목은 .selected를 붙여서 영구적으로 숨기고 selectedDataList에 추가한다. 이를 컴포넌트에 <lightning-pill>태그로 나열한다.
- 선택된 항목을 제거하는 경우, 해당 항목을 selectedDataList에서 제거하고 dataList에서 해당 항목의 .selected를 제거하여 다시 보여준다.
주의사항
- Dropdown에 click이벤트를 거는 경우 input의 focus가 우선순위로 빠져서 클릭하기 전에 dropdown이 먼저 숨는다. 따라서 dropdown에 mousedown이벤트를 걸어서 focus이벤트가 발생하기 전에 선택된 항목을 가로채야 한다.
- Dropdown을 <template if>로 처리할 경우 input에 focus가 발생했을때 rerender가 된다. 이는 동적으로 생성된 .slds-hide, .selected 클래스를 날려버리기 때문에 CSS를 통해 visibility를 조정을 하는 방식으로 만들어야 한다.
- Visibility조정이 아닌 dataList를 직접 건드려서 dropdown 항목을 제어할 경우, 선택된 항목을 제거해서 다시 돌려놓을때 정렬이 깨져버린다. 따라서 dataList를 직접 건드리면 안된다.
'Salesforce > LWC' 카테고리의 다른 글
자주 쓰는 기능을 모듈화 하는 방법 (0) | 2022.12.09 |
---|---|
Lightning Web Component의 등장 배경과 사용해야 하는 이유 (0) | 2022.12.02 |
template for:each에서 key는 무슨 역할을 하는걸까? (0) | 2022.11.26 |
Comments