Скрыть элемент, если у всех потомков есть класс
Всех приветствую. Задача такая:
Есть input (js-city-search), в который вводится текст. Если содержимое input'а не находит совпадений в текстовом содержимом элемента (js-map-cities__item), то элементу (js-map-cities__item) добавляется класс "hidden", который скрывает его. Если абсолютно все элементы (js-map-cities__item) внутри своего (js-spoiler-body) имеют класс "hidden", то ближайший выше по уровню предок (js-spoiler) тоже должен получать класс "hidden". Если хотя бы 1 js-map-cities__item будет без класса "hidden", то и js-spoiler его получать не должен.
В прикрепленном мною коде есть функционал скрытия js-map-cities__item. Но для решения остальной части задачи у меня знаний не хватает.
Буду благодарен за вашу помощь.
$(document).on('keyup', '.js-city-search', function keyupInput() {
const $inp = $(this);
const $inpValue = $inp.val();
const $items = $inp.closest('.map-cities').find('.js-search-body .js-map-cities__item');
$items.each(function citySearch(index, value) {
if (!value.innerHTML.toLowerCase().includes($inpValue.toLowerCase())) { // !== $inpValue
$(this).addClass('hidden');
} else {
$(this).removeClass('hidden');
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="map-cities">
<div class="map-cities__search">
<input type="search" name="" id="" placeholder="Поиск по региону" class="inp js-city-search" />
</div>
<div class="map-cities__body js-search-body">
<div class="map-cities__spoiler js-spoiler">
<a href="#" data-city-id="4" class="map-cities__spoiler-toggler js-toggle-spoiler">
<span>Белгородская область</span>
<span class="counter">(34)</span>
</a>
<div class="map-cities__spoiler-body js-spoiler-body">
<a href="#" data-balloon-id="461" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Николаево, улица Простая, 75<br />
</a>
<a href="#" data-balloon-id="462" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Петрово, улица Короткая, 3<br />
</a>
<a href="#" data-balloon-id="439" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Павловка, улица Советская, 2<br />
</a>
</div>
</div>
</div>
</div>
Ответы (2 шт):
Есть input (js-city-search), в который вводится текст. Если содержимое input'а не находит совпадений в текстовом содержимом элемента (js-map-cities__item), то элементу (js-map-cities__item) добавляется класс "hidden", который скрывает его. Если абсолютно все элементы (js-map-cities__item) внутри своего (js-spoiler-body) имеют класс "hidden", то ближайший выше по уровню предок (js-spoiler) тоже должен получать класс "hidden".
Предложу такой вариант решения такой задачи...
let t
$('.map-cities__search input').on('input', function(){
if (t) clearTimeout(t)
const v = this.value.toLowerCase()
t = setTimeout(test, 100, v)
});
//
function test(v){
$('.map-cities .off').removeClass('off')
if (v == '') return
$('.map-cities .map-cities__item').filter((_, o) => !o.textContent.toLowerCase().includes(v)).addClass('off')
$('.map-cities .js-spoiler:not(:has(.map-cities__item:not(.off)))').addClass('off')
}
.off {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="map-cities">
<div class="map-cities__search">
<input type="search" name="" id="" placeholder="Поиск по региону" class="inp js-city-search" />
</div>
<div class="map-cities__body js-search-body">
<div class="map-cities__spoiler js-spoiler">
<a href="#" data-city-id="4" class="map-cities__spoiler-toggler js-toggle-spoiler">
<span>Белгородская область</span>
<span class="counter">(34)</span>
</a>
<div class="map-cities__spoiler-body js-spoiler-body">
<a href="#" data-balloon-id="461" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Николаево, улица Простая, 75<br />
</a>
<a href="#" data-balloon-id="462" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Петрово, улица Короткая, 3<br />
</a>
<a href="#" data-balloon-id="439" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Павловка, улица Советская, 2<br />
</a>
</div>
</div>
</div>
</div>
С минимальными правками примера и логики решения:
$(document).on('keyup', '.js-city-search', function keyupInput() {
const $inp = $(this),
inpValue = $inp.val().trim().toLowerCase(),
$spoilers = $inp.closest('.map-cities').find('.js-search-body .js-spoiler');
$spoilers.each(function (index, sp) {
const $spoiler = $(sp),
$items = $spoiler.find('.js-map-cities__item');
$items.each(function citySearch(index, el) {
const elText = el.textContent.trim().toLowerCase();
$(el).toggleClass('hidden', !elText.includes(inpValue));
});
const notHiddenCnt = $spoiler.has('.js-map-cities__item:not(.hidden)').length;
$spoiler.toggleClass('hidden', !notHiddenCnt);
});
});
.hidden { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="map-cities">
<div class="map-cities__search">
<input type="search" name="" id="" placeholder="Поиск по региону" class="inp js-city-search" />
</div>
<div class="map-cities__body js-search-body">
<div class="map-cities__spoiler js-spoiler">
<a href="#" data-city-id="4" class="map-cities__spoiler-toggler js-toggle-spoiler">
<span>Белгородская область</span>
<span class="counter">(34)</span>
</a>
<div class="map-cities__spoiler-body js-spoiler-body">
<a href="#" data-balloon-id="461" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Николаево, улица Простая, 75<br />
</a>
<a href="#" data-balloon-id="462" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Петрово, улица Короткая, 3<br />
</a>
<a href="#" data-balloon-id="439" class="map-cities__item js-map-cities__item">
<b>Белгородская область</b>, Павловка, улица Советская, 2<br />
</a>
</div>
</div>
</div>
</div>
Суть в том что проходим по элементам "спойлеров", и (во вложенном цикле) по его элементам - сначала переключаем классы у элементов, затем у родителя.
Это неоптимальное, но самое простое решение задачи.
В качестве оптимизаций, лучше будет выполнять поиск по однократно сформированному словарю "текстЭлемента: элемент" исключив основную массу повторяемых действий, а также добавить в обработчик событий разрядку их частоты (паттерн debounce можно использовать, например).