Thursday, 18 March 2021

Custom Multi select dropdown using LWC

Recently i have worked on " multi select picklist" component required for my project. Showing you how to create it using LWC and hopefully you can use this component as your need.

it looks great and work beautifully , Lets enjoy ..!


multiselectdropdown.html


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
    <div class="slds-form-element">
     <label class="slds-form-element__label" for="combobox-id-5">Relate to</label>
        <div class="slds-form-element__control">
          <div class="slds-combobox_container slds-size_small">
            <section id="maindiv" class="slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open" aria-expanded="true" aria-haspopup="listbox" role="combobox">
              <div onclick={handleClick} onmouseleave={handleMouseOut} 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 slds-has-focus slds-combobox__input-value" id="combobox-id-5" aria-controls="listbox-id-5"  role="textbox" placeholder={defaultText} readonly=""
                />
            
                <span class="slds-icon_container slds-icon-utility-down slds-input__icon slds-input__icon_right">
                    <lightning-icon icon-name="utility:down" size="x-small" alternative-text="Approved"></lightning-icon>
                </span>
              </div>
              <template if:true={iswindowOpen}>
              <div onmouseenter={handlemouseOver} onmouseleave={handleMouseLeave} id="listbox-id-5" class="slds-dropdown slds-dropdown_length-5 slds-dropdown_fluid" role="listbox">
                <ul class="slds-listbox slds-listbox_vertical" role="presentation">
                <template for:each={_options} for:item="option">
                    <c-list-items key={option.value}
                                         value={option.value}
                                         label={option.label}
                                         selected={option.selected}
                                         onselected={handleSelectedClick}></c-list-items>
                    
                  </template>
                  </ul>
              </div>
            </template>

            </section>
          </div>
        </div>
      </div>
</template>



multiselectdropdown.js



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { LightningElement, api, track } from 'lwc';

export default class Multiselectdropdown extends LightningElement {
@api options = [{label:'Resource 1',value:'Resource 1',selected:false},
    {label:'Resource 2',value:'Resource 2',selected:false},
    {label:'Resource 3',value:'Resource 3',selected:false},
    {label:'Resource 4',value:'Resource 4',selected:false},
    {label:'Resource 5',value:'Resource 5',selected:false},
    {label:'Resource 6',value:'Resource 6',selected:false},
    {label:'Resource 7',value:'Resource 7',selected:false},
    {label:'Resource 8',value:'Resource 8',selected:false}];
    @api selectedValues=[];
    @api label=' ';
    @track _options= [];
    @track iswindowOpen=false;

  /*Init() call..*/
    connectedCallback() {
        this._options = JSON.parse(JSON.stringify(this.options));
        //sort all array items befor display it to ui
        this._options=this._options.sort(function compare(a,b) {
            if (a.value == 'All'){
              return -1;
            }
            else if (a.value < b.value){
              return -1;
            }
            if (a.value > b.value){
              return 1;
            }
            return 0;
          });
        
      }
      get defaultText(){
        if (this.selectedValues.length === 0) {
          return "Select an option...";
        }
        if (this.selectedValues.length === 1) {
          return this.selectedValues[0].label;
        }
        else{
          return this.selectedValues.length+" Options Selected";

        }
      }

      handleClick(event){
          console.log('query selector..'+this.template.querySelector("section"));
        this.iswindowOpen=true;
        this.template.querySelector("section").classList.add("slds-is-open");
      }

      handleMouseOut(event){
       if(this.iswindowOpen){
        return;
       }
       this.template.querySelector("section").classList.remove("slds-is-open");
      }

      handleMouseLeave(event){
        this.iswindowOpen=false;
        this.template.querySelector("section").classList.remove("slds-is-open");

      }

      handlemouseOver(event){
        this.iswindowOpen=true;
      }

      handleSelectedClick(event){

        var value;
        var selected;
        event.preventDefault();
        event.stopPropagation();
    
        const data = event.detail;
    
        value = data.value;
        selected = data.selected;
    
        //shift key ADDS to the list (unless clicking on a previously selected item)
        //also, shift key does not close the dropdown.
        if (data.shift) {
          this._options.forEach(function(option) {
            if (option.value === value) {
              option.selected = selected === true ? false : true;
            }
          });
        }
        else {
          this._options.forEach(function(option) {
            if (option.value === value) {
              option.selected = selected === "true" ? false : true;
            } else {
              option.selected = false;
            }
          });
         // this.closeDropdown();
        }
    
        this.selectedValues = this.getOptionsArray();
    
      }

      getOptionsArray(){
        var pills = [];
        this._options.forEach(function(element) {
          var interator = 0;
          if (element.selected) {
            pills.push({label:element.label, name:element.value, key: interator++});
          }
        });
        return pills;
      }
    

}


Child Component :

listItems.html



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<template>
    <li onclick={eventHandler} class="slds-listbox__item" role="presentation"  >
        <div class={listStyle} role="option">
          <span class="slds-media__figure">
            <lightning-icon icon-name="utility:check" size="x-small" alternative-text="selected" class="slds-icon-utility-check slds-current-color slds-listbox__icon-selected slds-icon_container"></lightning-icon>
          </span>
          <span class="slds-media__body">
            <span class="slds-truncate no-selection" title={label}>&nbsp;{label}</span>
          </span>
        </div>
      </li>
</template>

listItems.js



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { LightningElement,api,track } from 'lwc';

export default class ListItems extends LightningElement {

  @api key = '';
  @api value = '';
  @api label = '';
  @api selected = false;

  get listStyle() {
    var initial = ' slds-media  slds-listbox__option_plain slds-media_small slds-listbox__option ';
    return this.selected === true ? initial + ' slds-is-selected ' : initial ;
  }

  eventHandler(event) {
    event.preventDefault();
    event.stopPropagation();
    console.log('selcted value..'+this.selected);
    const selectedEvent = new CustomEvent('selected', { detail: {label:this.label,value:this.value,selected:this.selected,shift:event.shiftKey} });
    this.dispatchEvent(selectedEvent);
  }
}

Explanation..

in code we are using Shift key to select multiple options from dropdown. on select option(s) , events is getting fired from child component and being handled on parent component 
handleSelectedClick(event)

one tricky part is handling showing and hiding of drop down list using below two events:
  • onmouseenter
  • onmouseleave

OutPut :

Lets see the output and hope you will like it.

2 comments:

  1. its not working as like you shown in above vedio..

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete

Getting started with Heroku

I am familiar with the heroku for quite long time, have seen lots of people are interested with it but not sure from where its need to Start...