ES5 Javascript: получить уникальное значение из 2 селекторов и добавить/обновить в массив

На моей веб-странице есть 2 селектора: один - вкладка, а другой - раскрывающийся список. На основе кликов пользователя на вкладке и раскрывающемся списке я получаю значение клика и помещаю его в массив. В массиве не более 2 элементов — оба элемента должны быть уникальными значениями, сопоставленными с выбором вкладки и раскрывающегося списка соответственно:

Tag1 -> value from Tab selection
Tag2 -> value from drop down

Чтобы добавить/обновить массив в определенное место, я использовал Array.prototype.splice()

Мне удалось нажать значения выбора на вкладке и в раскрывающемся списке в массиве. Однако я столкнулся с некоторыми проблемными сценариями, как описано ниже.

Пожалуйста, смотрите тестовый код ниже:

// Get all tabs
var tabs = document.querySelectorAll('.tab')
// Get select element
var select = document.querySelector('select')
// Create tag array
var tags = []
var tagText = document.querySelector('#tags')

// Register click event listeners for tabs
if (tabs.length > 0) {
  tabs.forEach(function (tab) {
    tab.addEventListener('click', handleTabClick, true)
  })
}

// Register click event listener for select element
if (select) {
  select.addEventListener('change', handleSelectChange, true)
}

// Handle tab click
function handleTabClick(e) {
  var currentElement = e.target

  // Remove all active modifiers
  tabs.forEach(function (tab) {
    tab.classList.remove('active')
  })

  // Apply the active modifer to the current element
  currentElement.classList.add('active')

  // Update the UI showing the correct pane by ID
  var id = currentElement.dataset.targetPane

  if (id != 'tab-all') {
    // Add selected id to array
    tags.splice(0, 1, id)
  } else {
    tags.splice(0, 1, '')
  }

  tagText.innerHTML = tags
}

// Handle select change
function handleSelectChange(e) {
  var id = e.target.value

  if (id != 'all') {
    // Add selected id to array
    tags.splice(1, 1, id)
  } else {
    tags.splice(1, 1, '')
  }

  tagText.innerHTML = tags
}
.tabs {
  padding-left: 0;
  list-style-type: none;
  display: flex;
}

.tab {
  flex: 1;
  text-align: center;
  padding: 10px;
  cursor: pointer;
  color: #000000;
  border: 1px solid #d1d1d1;
}

.active {
  border-bottom: 3px solid red;
}
Tab options (1st in tags array): Tag 1
<ul class="tabs">
  <li class="tab active" data-target-pane="tab-all">All
  </li>
  <li class="tab" data-target-pane="finance">
    Finance
  </li>
  <li class="tab" data-target-pane="energy">
    Energy
  </li>
</ul>
Dropdown options (2nd in tags array): Tag 2
<label class="select">
  <select>
    <option value="all" selected="">All</option>
    <option value="whitepaper">Whitepaper</option>
    <option value="articles">Articles</option>
    <option value="video">Video</option>
  </select>
</label>
<p>Return tags array: <b><span id="tags"></span></b></p>
<p>Tag 1 -> value from Tab<br>
Tag 2 -> value from dropdown<br><br>Expect the tags array output to always be [Tag 1 , Tag 2].<br>Max 2 item in array. If user selected "All", empty the previous selection within the same Tag (1 or 2) array location.</p>

Сценарий проблемы (нежелательный результат)

1) Если пользователь сначала выбирает параметр раскрывающегося списка (Tag2), а затем выбирает другой параметр раскрывающегося списка (Tag2): массив тегов имеет [Tag2, Tag2]. Ожидается: [Тег2]

2) Если пользователь сначала выбирает раскрывающийся список (Tag2), а затем выбирает вкладку (Tag1): в массиве Tags сначала есть [Tag2], и он заменяется на [Tag1]. Ожидается: [тег2 , тег1]

3) Если пользователь сначала выбирает параметр раскрывающегося списка (Tag2), а затем выбирает другой параметр раскрывающегося списка (Tag2) и, наконец, выбирает значение раскрывающегося списка «Все» (Tag2): массив тегов сначала имеет [Tag2, Tag2] и с «Все ", он становится [Tag2,]. Ожидается: сначала [Tag2] и с выбранным «Все», []

Идеальный сценарий

1) Если пользователь сначала выбрал вкладку (Tag1), прежде чем выбрать параметр раскрывающегося списка (Tag2): Массив тегов должен получить [Tag1, Tag2].

2) Если пользователь выбрал «Все», очистите предыдущий выбор в том же месте массива тегов (1 или 2). Например, пользователь сначала выбрал вкладку (Tag1), а затем выбирает вкладку «Все». Массив тегов получает []. Если пользователь сначала выбрал вкладку (Tag1) и выбрал вариант раскрывающегося списка (Tag2), а затем выбрал значение «Все» в раскрывающемся списке. Массив тегов должен стать [Tag1]

Я ожидаю, что массив тегов будет одним из следующих:

1) Максимум 2 элемента в массиве -> [Tag1, Tag2] или [Tag2, Tag1]

2) Один элемент массива [Tag1] или [Tag2]

Но он никогда не должен иметь [Tag1, Tag1] или [Tag2, Tag2].

Короче говоря, массив должен иметь уникальные значения, соответствующие выбору вкладки и выбору раскрывающегося списка.


person Shiro    schedule 13.07.2019    source источник


Ответы (1)


Поскольку иногда вам нужен результат с [Тег 1, Тег 2], а иногда [Тег 2, Тег 1], было бы хорошо помнить, в каком слоте вы последний раз сохраняли выбор Тега 1, чтобы вы знали, какой из двух заменить.

Я предполагаю, что последний сделанный выбор всегда будет последним значением в массиве.

Поэтому я ввел переменную tabIndex, которая равна либо 0, либо 1. Кроме того, я адаптировал код так, чтобы он сначала удалял текущее значение из массива (из индекса, который может быть получен из tabIndex) а затем помещает выбранное значение в конец массива, одновременно обновляя tabIndex.

// Get all tabs
var tabs = document.querySelectorAll('.tab')
// Get select element
var select = document.querySelector('select')
// Create tag array
var tags = []
var tagText = document.querySelector('#tags')
var tabIndex = 0;

// Register click event listeners for tabs
tabs.forEach(function (tab) {
    tab.addEventListener('click', handleTabClick, true)
})

// Register click event listener for select element
if (select) {
  select.addEventListener('change', handleSelectChange, true)
}

// Handle tab click
function handleTabClick(e) {
    var currentElement = e.target

    // Remove all active modifiers
    tabs.forEach(function (tab) {
        tab.classList.remove('active')
    })

    // Apply the active modifer to the current element
    currentElement.classList.add('active')

    // Update the UI showing the correct pane by ID
    var id = currentElement.dataset.targetPane

    tags.splice(tabIndex, 1)
    if (id != 'tab-all') {
        // Add selected id to array
        tabIndex = tags.length
        tags.push(id)
    }
    tagText.textContent = JSON.stringify(tags)
}

// Handle select change
function handleSelectChange(e) {
    var id = e.target.value

    tags.splice(1-tabIndex, 1)
    if (id != 'all') {
        // Add selected id to array
        tabIndex = 1 - tags.length;
        tags.push(id)
    }

    tagText.textContent = JSON.stringify(tags)
}
.tabs {
  padding-left: 0;
  list-style-type: none;
  display: flex;
}

.tab {
  flex: 1;
  text-align: center;
  padding: 10px;
  cursor: pointer;
  color: #000000;
  border: 1px solid #d1d1d1;
}

.active {
  border-bottom: 3px solid red;
}
Tab options (1st in tags array): Tag 1
<ul class="tabs">
    <li class="tab active" data-target-pane="tab-all">All</li>
    <li class="tab" data-target-pane="finance">Finance</li>
    <li class="tab" data-target-pane="energy">Energy</li>
</ul>
Dropdown options (2nd in tags array): Tag 2
<label class="select">
  <select>
    <option value="all" selected="">All</option>
    <option value="whitepaper">Whitepaper</option>
    <option value="articles">Articles</option>
    <option value="video">Video</option>
  </select>
</label>
<p>Return tags array: <b><span id="tags"></span></b></p>
<p>Tag 1 -> value from Tab<br>
Tag 2 -> value from dropdown<br><br>Expect the tags array output to always be [Tag 1 , Tag 2].<br>Max 2 item in array. If user selected "All", empty the previous selection within the same Tag (1 or 2) array location.</p>

person trincot    schedule 13.07.2019