From 9d177262f500457fde7c03931f8209f6ab59c5e6 Mon Sep 17 00:00:00 2001 From: MaxOvs19 <88626313+MaxOvs19@users.noreply.github.com> Date: Mon, 10 Oct 2022 16:15:23 +0300 Subject: [PATCH] Feat/add multiselect (#5) * Fixed DRY and added new styles in item multiSelect * MultiSelectTag 90% done * Fixed and refactoring multiTag. Chips working! * Multiselect tag working, but repeates id for elements * Multi select full working! But refacrtoring TODO~ Co-authored-by: MaxOvs --- src/cg-dropdown.js | 162 +++++++++++++++++++++++++++++--------------- src/index.js | 25 +------ src/style/main.scss | 101 +++++++++++++++++---------- 3 files changed, 179 insertions(+), 109 deletions(-) diff --git a/src/cg-dropdown.js b/src/cg-dropdown.js index a858828..6d9e032 100644 --- a/src/cg-dropdown.js +++ b/src/cg-dropdown.js @@ -4,11 +4,12 @@ export class DropDown { #options; #caret; #items; - #value; + #selectedItems; + #id = []; #indexes = []; get value() { - return this.#value ?? null; + return this.#selectedItems ?? null; } get indexes() { @@ -17,7 +18,6 @@ export class DropDown { constructor(options = {}) { this.#init(options); - this.#initAmount(); this.#render(); this.#initEvent(); } @@ -73,7 +73,7 @@ export class DropDown { this.#items = items; if (multiselect) { - this.#value = []; + this.#selectedItems = []; } } @@ -102,23 +102,8 @@ export class DropDown { } } - #initAmount() { - const { amount } = this.#options; - - if (!amount) { - return; - } - - let templete = ''; - - for (let i = 0; i < amount; i++) { - templete += `
  • ${i + 1}
  • `; - } - this.#element.innerHTML += ``; - } - #render(select) { - const { items, styles, url, multiselect } = this.#options; + const { items, styles, url, multiselect, multiselectTag } = this.#options; if (select || (select && styles)) { this.#initSelected(select); @@ -127,7 +112,6 @@ export class DropDown { this.#initSelected(); } - this.#element.querySelector(this.#options.selector); const ul = document.createElement('ul'); if (styles) { @@ -153,14 +137,16 @@ export class DropDown { return; } - items.forEach((item) => { + items.forEach((item, index) => { const li = document.createElement('li'); let text = ''; + let id = ''; li.classList.add('list__item'); if (this.#checkItemStruct(item)) { text = item.title; + id = item.id; } else { text = item; } @@ -168,6 +154,15 @@ export class DropDown { if (multiselect) { const checkBox = document.createElement('input'); checkBox.type = 'checkbox'; + + if (multiselectTag) { + if (this.#checkItemStruct(item)) { + checkBox.setAttribute('id', `chbox-${item.id}`); + } else { + checkBox.setAttribute('id', `chbox-${index}`); + } + } + li.appendChild(checkBox); } @@ -194,12 +189,11 @@ export class DropDown { const response = await fetch(url); const data = await response.json(); - //ToDO: fix title(item.title!) this.#items = []; data.forEach((dataItem, index) => { const item = { - id: dataItem.id, + id: dataItem.phone, title: dataItem.name, value: index, }; @@ -209,6 +203,9 @@ export class DropDown { const checkBox = document.createElement('input'); checkBox.type = 'checkbox'; + + checkBox.setAttribute('id', `chbox-${item.id}`); + li.appendChild(checkBox); li.classList.add('list__item'); @@ -240,9 +237,12 @@ export class DropDown { const options = this.#element.querySelectorAll('.list__item'); const selected = this.#element.querySelector('.selected'); - // const ul = document.createElement('ul'); + const ul = document.createElement('ul'); - // ul.classList.add('multiselectTag'); + if (multiselect) { + ul.classList.add('multiselect-tag'); + selected.classList.add('overflow-hidden'); + } options.forEach((option, index) => { option.addEventListener('click', (event) => { @@ -260,49 +260,55 @@ export class DropDown { } const checkIndex = this.#indexes.indexOf(index); + let value = ''; + let id = ''; - let templete = ''; if (checkIndex === -1) { this.#indexes.push(index); if (this.#checkItemStruct(item)) { - this.#value.push(item.title); + this.#selectedItems.push(item.title); + value = item.title; + id = item.id; } else { - this.#value.push(item); + this.#selectedItems.push(item); + value = item; } - //TODO refactoring code!!!! + selected.innerText = ''; + if (multiselectTag) { - for (let i = 0; i < this.#value.length; i++) { - templete += `
  • ${this.#value[i]}
  • `; + selected.appendChild(ul); + + if (this.#checkItemStruct(item)) { + ul.appendChild(this.#createBreadcrumb(value, index, id)); + } else { + ul.appendChild(this.#createBreadcrumb(value, index)); } - - selected.innerHTML = ``; } else { - selected.innerText = this.#value; + selected.innerText = this.#selectedItems; } + } else { + if (multiselectTag) { + const tagItem = document.getElementById(`tag-${index}`); - return; + ul.removeChild(tagItem); + + this.#indexes.splice(checkIndex, 1); + this.#selectedItems.splice(checkIndex, 1); + } else { + this.#indexes.splice(checkIndex, 1); + this.#selectedItems.splice(checkIndex, 1); + } } - this.#indexes.splice(checkIndex, 1); - this.#value.splice(checkIndex, 1); - - if (multiselectTag) { - for (let i = 0; i < this.#value.length; i++) { - templete += `
  • ${this.#value[i]}
  • `; - } - - selected.innerHTML = ``; - } - - if (!this.#value.length) { + if (!this.#selectedItems.length) { selected.innerText = placeholder; } else { if (multiselectTag) { - selected.innerHTML = ``; + selected.appendChild(ul); } else { - selected.innerText = this.#value; + selected.innerText = this.#selectedItems; } } } @@ -312,8 +318,7 @@ export class DropDown { } else { selected.innerText = item; } - - this.#value = item; + this.#selectedItems = item; options.forEach((option) => { option.classList.remove('active'); @@ -324,6 +329,57 @@ export class DropDown { }); } + #createBreadcrumb(value, index, id) { + const { placeholder } = this.#options; + + const selected = this.#element.querySelector('.selected'); + + const li = document.createElement('li'); + const text = document.createTextNode(value); + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + + svg.setAttribute('viewBox', '0 0 10 10'); + path1.setAttribute('d', 'M3,7 L7,3'); + path2.setAttribute('d', 'M3,3 L7,7'); + li.setAttribute('id', `tag-${index}`); + + svg.classList.add('svg-icon'); + + svg.appendChild(path1); + svg.appendChild(path2); + li.appendChild(text); + li.appendChild(svg); + + svg.addEventListener('click', (event) => { + event.stopPropagation(); + + const deleteIcon = this.#indexes.indexOf(index); + + this.#indexes.splice(deleteIcon, 1); + this.#selectedItems.splice(deleteIcon, 1); + + let checkBox = ''; + if (id) { + checkBox = document.getElementById(`chbox-${id}`); + } else { + checkBox = document.getElementById(`chbox-${index}`); + } + + checkBox.checked = false; + checkBox.parentElement.classList.remove('active'); + + if (!this.#selectedItems.length) { + selected.innerText = placeholder; + } + + li.parentElement.removeChild(li); + }); + + return li; + } + #initEvent() { const { event } = this.#options; if (!event) { @@ -381,7 +437,7 @@ export class DropDown { if (content) { this.#element.innerHTML = `
    - ${content} +

    ${content}

    `; diff --git a/src/index.js b/src/index.js index eaa4547..42dfb2d 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ const dropdown = new DropDown({ dropdown.addItem('ZAZ'); dropdown.addItem('LADA'); +// dropdown.addItem('BMW'); const dropdown2 = new DropDown({ selector: '.cg-dropdown2', @@ -42,15 +43,9 @@ const dropdown2 = new DropDown({ }, ], multiselect: true, + multiselectTag: true, }); -setTimeout(() => { - console.log(dropdown.value); -}, 10000); -setTimeout(() => { - console.log(dropdown.indexes); -}, 10000); - //ToDo: paste the desired url; const dropdown3 = new DropDown({ @@ -58,19 +53,5 @@ const dropdown3 = new DropDown({ placeholder: 'URL', url: 'http://jsonplaceholder.typicode.com/users', multiselect: true, + multiselectTag: true, }); - -// const dropdown3 = new DropDown({ -// selector: '.cg-dropdown3', -// selected: '', -// items: [ -// { -// title: 'Russia', -// item: ['Rostov', 'Moskow'], -// }, -// { -// title: 'Germany', -// item: ['Germany', 'Berlin'], -// }, -// ], -// }); diff --git a/src/style/main.scss b/src/style/main.scss index 0742c1f..6c49ab9 100644 --- a/src/style/main.scss +++ b/src/style/main.scss @@ -19,16 +19,15 @@ body { } .cg-select { - padding: 14px; - min-width: 200px; - max-width: 200px; - height: 30px; + padding: 5px; + min-width: 225px; + max-width: 225px; + min-height: 50px; color: #fff; display: flex; justify-content: space-between; align-items: center; - overflow: hidden; text-overflow: ellipsis; background: #2a2f3b; cursor: pointer; @@ -36,9 +35,8 @@ body { transition: 0.5s; .selected { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + max-width: 200px; + margin: 5px; } &:hover { @@ -47,9 +45,16 @@ body { } } +.overflow-hidden { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .caret { width: 0; height: 0; + margin-right: 10px; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 6px solid #fff; @@ -65,7 +70,7 @@ body { max-height: 230px; overflow-y: auto; position: absolute; - width: 212px; + width: 220px; padding: 7px; margin-top: -0.2px; list-style: none; @@ -93,6 +98,59 @@ body { } } +.multiselect-tag { + display: flex; + flex-wrap: wrap; + flex-direction: row; + align-items: center; + + list-style-type: none; + margin: 0; + padding: 0; + + li { + padding: 2px 4px 2px 4px; + background: #76767659; + height: 20px; + margin: 0 5px 5px 0; + + display: flex; + align-items: center; + + position: relative; + border-radius: 5px; + } + &__button { + width: 15px; + height: 16px; + border: none; + } +} + +input[type='checkbox'] { + cursor: pointer; +} + +.svg-icon { + width: 16px; + margin-left: 3px; + background-color: #bebebc; + border-radius: 5px; + cursor: pointer; + transition: 1s; + + &:hover { + transition: 1s; + background-color: #ffffff; + } +} +.svg-icon path { + color: black; + stroke: currentcolor; + transition: 0.2s; + stroke-width: 0.5; +} + .active { background: #8282822c; } @@ -114,28 +172,3 @@ body { ::-webkit-scrollbar-thumb { background-color: #4d4d4d; } - -.multiselect { - height: 20px; - - display: flex; - align-items: center; - - li { - color: red; - border: 1px solid #4d4d4d; - } - z-index: 999; -} - -.multiselectTag { - display: flex; - text-decoration: none; - flex-direction: row; - height: 15px; - list-style-type: none; -} - -input[type='checkbox'] { - cursor: pointer; -}