Объединение выбора 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 шт):
Я бы добавил возможное количество тарифов в объект, допустим так:
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: Изменил данные, теперь тарифов можно сделать сколько угодно и различные данные.
Так же вывод данных сделан по типу шаблонизаторов.