Объединение выбора select с таблицами тарифов + изменения цены и скорости

Есть последовательный выбор select, нужно сначала выбрать район, потом город, из-за этого выбора должен измениться тариф и скорость. Сейчас выводится 1 тариф в и меняется его цена после выбора города.
Хотел спросить, как лучше организовать условие, в котором у каждого города может быть разное количество тарифов, например у одного 2, у второго 4 (это максимум) и как это лучше оформить и задать в коде
При этом ещё должна менятся скорость тарифа, если потом прятать таблицы через css(ну или добавлять/убирать колонки). Я немного запутался уже, по этому решил попросить о помощи.

const aData = {
  Мордовийский: {
    '---': 0,
    'г. Омаровка': 100
  },
  Культовский: {
    '---': 0,
    'г. Подлужайск': 100,
    'с. Припятское': 2100,
  },
  Сталкерский: {
    '---': 0,
    'с. Чернобыльское': 1300,
    'г. Теньчернобыльское': 1200,
  }
};

toggleSel.addEventListener("change", function() {
  result.innerHTML = "";
  if (toggleSel.value !== "---") {
    console.log(aData[toggleSel.value]);
    var obj = aData[toggleSel.value];
    Object.keys(obj).forEach(key => {
      console.log(key, obj[key]);
      result.appendChild(new Option(key, obj[key]))
    });
    result.removeAttribute("disabled");
  } else {
    result.setAttribute("disabled", "");
  }
  fCustomSelectUpdate(result);
});


result.addEventListener("change", () => {
  // Вывод результата
  document.getElementById('price1').innerHTML = result.value;
});

/* Закрытие неактивных списков */
function fCustomSelectClose(ev) {
  document.querySelectorAll(".sel-container.open").forEach((el) => el.classList.toggle("open", ev.target.closest(".sel-container.open") == el));
}
document.addEventListener("click", fCustomSelectClose);

/* Добавление обёртки */
function fCustomSelectInit(oSelect) {
  let width = getComputedStyle(oSelect).width;
  oSelect.style.display = "none";
  oSelect.insertAdjacentHTML("afterend", `
<div class="sel-container" style=" width: ${width};">
<a class="sel-single">${oSelect.value}</a>
<div class="sel-drop">
<div class="sel-search"><input autocomplete="off"></div>
<ul class="sel-results"></ul>
</div>
</div>
`);
  let oSelContainer = oSelect.nextElementSibling;
  let oSelSingle = oSelContainer.querySelector(".sel-single");
  let oSelSearch = oSelContainer.querySelector(".sel-search");
  let oSelSearchInput = oSelSearch.querySelector("input");
  let oSelResults = oSelContainer.querySelector(".sel-results");

  oSelSingle.addEventListener("click", function() {
    oSelContainer.classList.toggle("open");
  });
  oSelSearchInput.addEventListener("input", function() {
    let rExp = new RegExp(`(?:\\s|^)${this.value}`, "gi");
    oSelResults.querySelectorAll("li").forEach((el) => el.classList.toggle("active-result", el.textContent.search(rExp) != -1));
  });
  oSelResults.addEventListener("click", function(ev) {
    if (ev.target.tagName != "LI") return false;
    oSelSingle.textContent = ev.target.textContent;
    oSelect.selectedIndex = ev.target.dataset.index;
    oSelect.dispatchEvent(new Event("change"));
    oSelContainer.classList.toggle("open");
  });
}
document.querySelectorAll(".sel-group").forEach((el) => fCustomSelectInit(el));

/* Обновление пунктов в обёртке */
function fCustomSelectUpdate(oSelect) {
  let oSelContainer = oSelect.nextElementSibling;
  let oSelResults = oSelContainer.querySelector(".sel-results");
  oSelResults.innerHTML = "";
  oSelect.querySelectorAll("option").forEach((el, i) => {
    oSelResults.insertAdjacentHTML("beforeend", `<li class="active-result" data-index="${i}">${el.textContent}</li>`);
  });
  oSelect.dispatchEvent(new Event("change"));
  oSelContainer.querySelector(".sel-single").textContent = oSelect.value;
}
fCustomSelectUpdate(toggleSel);



/*
document.getElementById("#price2").textContent = result.value;
*/
body {
  display: flex;
  justify-content: center;
}

legend {
  font: bold 14px serif;
}

.sel-group {
  width: 200px;
}

.sel-container {
  position: relative;
  display: inline-block;
  vertical-align: middle;
  box-sizing: border-box;
  font: 13px sans-serif;
  user-select: none;
}

.sel-group[disabled]+.sel-container {
  filter: contrast(50%) brightness(150%);
  pointer-events: none;
}

.sel-single {
  position: relative;
  display: block;
  height: 25px;
  padding: 0 25px 0 8px;
  overflow: hidden;
  border: 1px solid #aaa;
  border-radius: 5px;
  box-sizing: border-box;
  line-height: 25px;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-decoration: none;
  color: #444;
  background-color: #fff;
  background-image: linear-gradient( to bottom, #fff 20%, #f6f6f6 50%, #eee 52%, #f4f4f4 100%);
  background-clip: padding-box;
  box-shadow: 0 0 3px #fff inset, 0 1px 1px rgb(0 0 0 / 10%);
}

.open .sel-single {
  border-radius: 5px 5px 0 0;
  background-image: linear-gradient( to top, #fff 20%, #f6f6f6 50%, #eee 52%, #f4f4f4 100%);
}

.sel-single::after {
  content: "\25BC";
  position: absolute;
  top: 0;
  right: 0;
  display: block;
  height: 25px;
  width: 20px;
  line-height: 25px;
}

.open .sel-single::after {
  transform: scaley(-1);
}

.sel-search {
  position: relative;
  display: none;
  padding: 3px 4px 3px 4px;
  box-sizing: border-box;
  font-size: 13px;
}

[data-search-input]+.sel-container .sel-search {
  display: block;
}

.sel-search::after {
  content: "\1F50D";
  position: absolute;
  top: 0;
  right: 0;
  display: block;
  height: 31px;
  width: 23px;
  line-height: 31px;
  color: #aaa;
  pointer-events: none;
}

.sel-search input {
  height: 25px;
  width: 100%;
  padding: 0px 20px 0px 2px;
  box-sizing: border-box;
}

.sel-drop {
  position: absolute;
  top: 100%;
  z-index: 1000;
  margin-top: -1px;
  width: 100%;
  border: 1px solid #aaa;
  border-top: 0;
  border-radius: 0 0 4px 4px;
  box-sizing: border-box;
  background: #fff;
  background-clip: padding-box;
  box-shadow: 0 4px 5px rgb(0 0 0 / 15%);
  clip: rect(0, 0, 0, 0);
  -webkit-clip-path: inset(100% 100%);
  clip-path: inset(100% 100%);
}

.open .sel-drop {
  clip: auto;
  -webkit-clip-path: none;
  clip-path: none;
}

.sel-results {
  position: relative;
  margin: 0 4px 4px 0;
  max-height: 240px;
  padding: 0 0 0 4px;
  box-sizing: border-box;
  overflow: hidden auto;
  color: #444;
}

.sel-results li {
  margin: 0;
  display: none;
  padding: 5px 6px;
  list-style: none;
  line-height: 15px;
  word-wrap: break-word;
}

.sel-results li.active-result {
  display: list-item;
  cursor: pointer;
}

.sel-results li:hover {
  color: #fff;
  background-image: linear-gradient(to bottom, #53b2fc, #1385e5);
}

@charset "UTF-8";
.pricingTable {
  margin: 40px auto;
}

.pricingTable>.pricingTable-title {
  text-align: center;
  color: #6e768d;
  font-size: 3em;
  font-size: 300%;
  margin-bottom: 20px;
  letter-spacing: 0.04em;
}

.pricingTable>.pricingTable-subtitle {
  text-align: center;
  color: #b4bdc6;
  font-size: 1.8em;
  letter-spacing: 0.04em;
  margin-bottom: 60px;
}

@media screen and (max-width: 480px) {
  .pricingTable>.pricingTable-subtitle {
    margin-bottom: 30px;
  }
}

.pricingTable-firstTable {
  list-style: none;
  padding-left: 2em;
  padding-right: 2em;
  text-align: center;
}

.pricingTable-firstTable_table {
  vertical-align: middle;
  width: 31%;
  background-color: #ffffff;
  display: inline-block;
  padding: 0px 30px 40px;
  text-align: center;
  max-width: 320px;
  transition: all 0.3s ease;
  border-radius: 5px;
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table {
    display: block;
    width: 90%;
    margin: 0 auto;
    max-width: 90%;
    margin-bottom: 20px;
    padding: 10px;
    padding-left: 20px;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table>* {
    display: inline-block;
    vertical-align: middle;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table>* {
    display: block;
    float: none;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table:after {
    display: table;
    content: "";
    clear: both;
  }
}

.pricingTable-firstTable_table:hover {
  transform: scale(1.08);
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table:hover {
    transform: none;
  }
}

.pricingTable-firstTable_table:not(:last-of-type) {
  margin-right: 3.5%;
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table:not(:last-of-type) {
    margin-right: auto;
  }
}

.pricingTable-firstTable_table:nth-of-type(2) {
  position: relative;
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table:nth-of-type(2) h1 {
    padding-top: 8%;
  }
}

.pricingTable-firstTable_table:nth-of-type(2):before {
  content: "Most Popular";
  position: absolute;
  color: white;
  display: block;
  background-color: #3bbdee;
  text-align: center;
  right: 15px;
  top: -25px;
  height: 65px;
  width: 65px;
  border-radius: 50%;
  box-sizing: border-box;
  font-size: 0.5em;
  padding-top: 22px;
  text-transform: uppercase;
  letter-spacing: 0.13em;
  transition: all 0.5s ease;
}

@media screen and (max-width: 988px) {
  .pricingTable-firstTable_table:nth-of-type(2):before {
    font-size: 0.6em;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table:nth-of-type(2):before {
    left: 10px;
    width: 45px;
    height: 45px;
    top: -10px;
    padding-top: 13px;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table:nth-of-type(2):before {
    font-size: 0.8em;
  }
}

.pricingTable-firstTable_table:nth-of-type(2):hover:before {
  transform: rotate(360deg);
}

.pricingTable-firstTable_table__header {
  font-size: 1.6em;
  padding: 40px 0px;
  border-bottom: 2px solid #ebedec;
  letter-spacing: 0.03em;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__header {
    font-size: 1.45em;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__header {
    padding: 0px;
    border-bottom: none;
    float: left;
    width: 33%;
    padding-top: 3%;
    padding-bottom: 2%;
  }
}

@media screen and (max-width: 610px) {
  .pricingTable-firstTable_table__header {
    font-size: 1.3em;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table__header {
    float: none;
    width: 100%;
    font-size: 1.8em;
    margin-bottom: 5px;
  }
}

.pricingTable-firstTable_table__pricing {
  font-size: 3em;
  padding: 30px 0px;
  border-bottom: 2px solid #ebedec;
  line-height: 0.7;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__pricing {
    font-size: 2.8em;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__pricing {
    border-bottom: none;
    padding: 0;
    float: left;
    clear: left;
    width: 33%;
  }
}

@media screen and (max-width: 610px) {
  .pricingTable-firstTable_table__pricing {
    font-size: 2.4em;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table__pricing {
    float: none;
    width: 100%;
    font-size: 3em;
    margin-bottom: 10px;
  }
}

.pricingTable-firstTable_table__pricing span:first-of-type {
  font-size: 0.35em;
  vertical-align: top;
  letter-spacing: 0.15em;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__pricing span:first-of-type {
    font-size: 0.3em;
  }
}

.pricingTable-firstTable_table__pricing span:last-of-type {
  vertical-align: bottom;
  font-size: 0.3em;
  letter-spacing: 0.04em;
  padding-left: 0.2em;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__pricing span:last-of-type {
    font-size: 0.25em;
  }
}

.pricingTable-firstTable_table__options {
  list-style: none;
  padding: 15px;
  font-size: 0.9em;
  border-bottom: 2px solid #ebedec;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__options {
    font-size: 0.85em;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__options {
    border-bottom: none;
    padding: 0;
    margin-right: 10%;
  }
}

@media screen and (max-width: 610px) {
  .pricingTable-firstTable_table__options {
    font-size: 0.7em;
    margin-right: 8%;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table__options {
    font-size: 1.3em;
    margin-right: none;
    margin-bottom: 10px;
  }
}

.pricingTable-firstTable_table__options>li {
  padding: 8px 0px;
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__options>li {
    text-align: left;
  }
}

@media screen and (max-width: 610px) {
  .pricingTable-firstTable_table__options>li {
    padding: 5px 0;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table__options>li {
    text-align: center;
  }
}

.pricingTable-firstTable_table__options>li:before {
  content: "✓";
  display: inline-block;
  margin-right: 15px;
  color: white;
  background-color: #74ce6a;
  border-radius: 50%;
  width: 15px;
  height: 15px;
  font-size: 0.8em;
  padding: 2px;
  text-align: center;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__options>li:before {
    width: 14px;
    height: 14px;
    padding: 1.5px;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__options>li:before {
    width: 12px;
    height: 12px;
  }
}

.pricingTable-firstTable_table__getstart {
  color: white;
  background-color: #71ce73;
  margin-top: 30px;
  border-radius: 5px;
  cursor: pointer;
  padding: 15px;
  box-shadow: 0px 3px 0px 0px #66ac64;
  letter-spacing: 0.07em;
  transition: all 0.4s ease;
}

@media screen and (max-width: 1068px) {
  .pricingTable-firstTable_table__getstart {
    font-size: 0.95em;
  }
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__getstart {
    margin-top: 0;
  }
}

@media screen and (max-width: 610px) {
  .pricingTable-firstTable_table__getstart {
    font-size: 0.9em;
    padding: 10px;
  }
}

@media screen and (max-width: 480px) {
  .pricingTable-firstTable_table__getstart {
    font-size: 1em;
    width: 50%;
    margin: 10px auto;
  }
}

.pricingTable-firstTable_table__getstart:hover {
  transform: translateY(-10px);
  box-shadow: 0px 40px 29px -19px rgba(102, 172, 100, 0.9);
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__getstart:hover {
    transform: none;
    box-shadow: none;
  }
}

.pricingTable-firstTable_table__getstart:active {
  box-shadow: inset 0 0 10px 1px #66a564, 0px 40px 29px -19px rgba(102, 172, 100, 0.95);
  transform: scale(0.95) translateY(-9px);
}

@media screen and (max-width: 767px) {
  .pricingTable-firstTable_table__getstart:active {
    transform: scale(0.95) translateY(0);
    box-shadow: none;
  }
}

body {
  font-family: "Montserrat", sans-serif;
  font-size: 100%;
  background-color: #f0f4f7;
  color: #717787;
}

@media screen and (max-width: 960px) {
  body {
    font-size: 80%;
  }
}

@media screen and (max-width: 776px) {
  body {
    font-size: 70%;
  }
}

@media screen and (max-width: 496px) {
  body {
    font-size: 50%;
  }
}

@media screen and (max-width: 320px) {
  body {
    font-size: 40%;
  }
}

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>qq3</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
  <link rel="stylesheet" href="./style.css">
</head>

<body>
  <div>
    <fieldset>
      <legend>Выберите Ваш район</legend>
      <!-- Чтобы появилось поле поиска, добавьте атрибут "data-search-input" -->
      <select class="sel-group" id="toggleSel">
        <option>---</option>
        <option>Мордовийский</option>
        <option>Культовский</option>
        <option>Сталкерский</option>
      </select>
    </fieldset>

    <fieldset>
      <legend>Выберите Ваш город/посёлок</legend>
      <select class="sel-group" id="result" data-search-input disabled></select>
    </fieldset>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.5.1/chosen.jquery.min.js"></script>
    <script src='https://codepen.io/qwerty_wasd/pen/aKbRrO.js'></script>
    <script src="./script.js"></script>
  </div>

  <!-- -->

  <div class="pricingTable">

    <ul class="pricingTable-firstTable">
      <li class="pricingTable-firstTable_table">
        <h1 class="pricingTable-firstTable_table__header">Базовый</h1>
        <p class="pricingTable-firstTable_table__pricing"><span>₴</span><span id="price1">0</span><span>месяц</span></p>
        <ul class="pricingTable-firstTable_table__options">
          <li>50 Mbit/s</li>
          <li>Edit Your Listing</li>
          <li>Approve Reviews</li>
        </ul>

        <div class="pricingTable-firstTable_table__getstart">Подключить</div>
      </li>
      <li class="pricingTable-firstTable_table">
        <h1 class="pricingTable-firstTable_table__header">Стандартный</h1>
        <p class="pricingTable-firstTable_table__pricing"><span>₴</span><span id="price2">0</span><span>Месяц</span></p>
        <ul class="pricingTable-firstTable_table__options">
          <li>100 Mbit/s</li>
          <li>Edit Your Listing</li>
          <li>Approve Reviews</li>
        </ul>



        <div class="pricingTable-firstTable_table__getstart">Подключить</div>
      </li>
      <li class="pricingTable-firstTable_table">
        <h1 class="pricingTable-firstTable_table__header">Быстрый</h1>
        <p class="pricingTable-firstTable_table__pricing"><span>$</span><span>0</span><span>месяц</span></p>
        <ul class="pricingTable-firstTable_table__options">
          <li>500 Mbit/s</li>
          <li>Edit Your Listing</li>
          <li>Approve Reviews</li>
        </ul>
        <div class="pricingTable-firstTable_table__getstart">Подключиь</div>
      </li>
      <li class="pricingTable-firstTable_table">
        <h1 class="pricingTable-firstTable_table__header">Максимальный</h1>
        <p class="pricingTable-firstTable_table__pricing"><span>₴</span><span>0</span><span>месяц</span></p>
        <ul class="pricingTable-firstTable_table__options">
          <li>1000 Mbit/s</li>
          <li>Edit Your Listing</li>
          <li>Approve Reviews</li>
        </ul>
        <div class="pricingTable-firstTable_table__getstart">Подключить</div>
      </li>
    </ul>
  </div>
  </hr>
</body>

</html>


Ответы (1 шт):

Автор решения: De.Minov

Я бы добавил возможное количество тарифов в объект, допустим так:

const tmp = `<div class="item">
    <div class="-title">%NAME%</div>
    <div class="-price">%PRICE%</div>
    <div class="-speed">%SPEED%</div>
  </div>`;

const aData = {
  'Мордовийский': {
    'г. Омаровка': [
      {name: 'Тариф 1', price: 100, speed: 10},
      {name: 'Тариф 3', price: 300, speed: 50}
    ]
  },
  'Культовский': {
    'г. Подлужайск': [
      {name: 'Тариф 1', price: 500, speed: 10},
      {name: 'Тариф 2', price: 750, speed: 50},
      {name: 'Тариф 3', price: 1250, speed: 100},
      {name: 'Тариф 4', price: 1750, speed: 150}
    ],
    'с. Припятское': [
      {name: 'Тариф 1', price: 250, speed: 25},
      {name: 'Тариф 4', price: 1000, speed: 100}
    ]
  },
  'Сталкерский': {
    'с. Чернобыльское': [
      {name: 'Тариф 4', price: 2500, speed: 250}
    ],
    'г. Теньчернобыльское': [
      {name: 'Тариф 2', price: 750, speed: 50},
      {name: 'Тариф 3', price: 1250, speed: 100}
    ],
  }
};

let region = document.querySelector('#region'),
    city = document.querySelector('#city'),
    priceEl = document.querySelector('#price');


region.insertAdjacentHTML('beforeend', '<option style="display:none">Выберите район</option>');

for(let key in aData) {
  region.insertAdjacentHTML('beforeend', '<option>'+key+'</option>');
}

region.addEventListener('change', function(e) {
  let val = e.target.value;
  city.innerHTML = '<option style="display:none">Выберите город</option>';
  for(let key in aData[val]) {
    city.insertAdjacentHTML('beforeend', '<option>'+key+'</option>');
  }
  priceEl.innerHTML = '';
});

city.addEventListener('change', function(e) {
  let pricing = aData[region.value][city.value];
  priceEl.innerHTML = '';
  pricing.forEach(function(e,i) {
    let temp = tmp;
    
    temp = temp.replace(/%NAME%/gm, e.name)
               .replace(/%PRICE%/gm, e.price)
               .replace(/%SPEED%/gm, e.speed);
    
    priceEl.insertAdjacentHTML('beforeend', temp);
  });
});
h1 {
  margin: 0 0 .5em;
  font-size: 140%;
  text-align: center;
}

#price {
  display: flex;
  flex-direction: row;
  justify-content: center;
  padding: 3em;
}

#price .item {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: .5em;
  box-sizing: border-box;
  text-align: center;
}

#price .item:not(:last-child) {
  margin-right: 2em;
}

#price .-price::after {
  content: '$';
  display: inline;
}

#price .-speed::after {
  content: 'mbit/s';
  display: inline;
}
<select id="region"></select>
<select id="city"></select>
<hr>
<h1>Выберите тариф</h1>
<div id="price"></div>

UPD: Изменил данные, теперь тарифов можно сделать сколько угодно и различные данные.
Так же вывод данных сделан по типу шаблонизаторов.

→ Ссылка