Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Включить/отключить checkbox при включении нескольких других checkbox (https://javascript.ru/forum/misc/78653-vklyuchit-otklyuchit-checkbox-pri-vklyuchenii-neskolkikh-drugikh-checkbox.html)

Aruta 16.10.2019 10:05

laimas,
Простите, если я не прав и туплю:)
Но ведь это родитель основного флажка и блока со второстепенными.
на нём висит ваш код и код показать/скрыть дочерний блок .upsale__block__bot-right__sub-wrap, который выступает обёрткой для блоков со второстепенными чекбоксами.

Т.е. обработчик чекбокса там только один - ваш, а прерывание висит, чтобы при нажатии на чекбокс не срабатывал скрипт показать/скрыть блок

laimas 16.10.2019 10:26

Цитата:

Сообщение от Aruta
Но ведь это родитель основного флажка и блока со второстепенными.

Ну естественно, ведь вы делегируете обработку флажков родителю. А в ней помимо моего кода и ваш, следовательно, если change не работает и заменить его на click, то не кучу обработчиков нужно вешать на родителя или на родителя плюс конкретный флажок, а либо в одном обработчике проверять источник и выполнять нужные операции или же разделять обработку событий посредством пространства имен.

Aruta 16.10.2019 13:08

laimas,
Я наверное тупой :cray:
НО загвоздка не в главном чекбоксе, а то что событие клика не назначено на родителя второстепенных чекбоксов, чтобы активировать дочерний чекбокс.

Схематично если, то сейчас:
блок 1 > input.
click происходит по умолчанию на input, чтобы галка встала.

А надо:
блок 1 > input
click должен быть на блок 1, чтобы галка встала в input.

Представим что input в состоянии disabled и меняет своё состояние при нажатии на (в данном случае) родителя. Но при этом должен работать и тот код, который влияет на главный чекбокс.

laimas 16.10.2019 13:15

Цитата:

Сообщение от Aruta
событие клика не назначено на родителя второстепенных чекбоксов

И как это понять?

Цитата:

Сообщение от Aruta
блок 1 > input.
click происходит по умолчанию на input, чтобы галка встала.

А надо:
блок 1 > input
click должен быть на блок 1, чтобы галка встала в input.

А это как переварить? Это "click происходит по умолчанию на input, чтобы галка встала" есть глупость, ибо установка и сброс флажка совершается одним и тем же действием, щелчком по нему, то бишь это всегда будет событие click.

Aruta 16.10.2019 14:06

laimas,
.upsale__block__sub-right-wrap - родитель для всех блоков и на него вешается событие клика (show/hide блок) для .upsale__block__bot-right__sub-wrap

второстепенные input должны срабатывать при клике на .floor__item-wrap. Выше не надо подниматься для события click по этому чекбоксу

Получается логика такая:
кликаем на .floor__item-wrap и дочерний для него чекбокс получает/снимает с себя галку, а далее уже работает функция установки и проверки состояния on/off для главного чекбокса.

Чтобы не путаться, то можно сделать второстепенные чекбоксы как disabled (в html хардкодом) и, тогда нужно обработчик клика по чекбоксу перенести на .floor__item-wrap.
Вот именно этот перенос обработчика клика и нужно добавить в ваш код, чтобы всё работало не конфликтуя:)

Порядок (при клике на .floor__item-wrap):
click по .floor__item-wrap -> проверка состояния дочернего input для этого блока -> ставим/снимаем галку в input (if есть галка уже/нет галки) -> проверка на состояние остальных input в оставшихся .floor__item-wrap -> снятие/установка галки в inpit в .upsale__block__bot-right__title-wrap

<div class="upsale__block__sub-right-wrap">
						<div class="upsale__block__bot-right__title-wrap dflex">
							<div class="upsale__block__bot-right__title dflex">
								<input id="floor" type="checkbox" class="block__check" onclick="event.stopPropagation()"> // этот input "главный". stopPropagation() добавлен, чтобы при нажатии на input не срабатывал скрипт click для upsale__block__bot-right__title-wrap			
								<span>
									<img class="arrow arrow-up" src="" alt="arrow_down">
									Choose your floor
								</span>
							</div>
							<div class="col-title__price-wrap dflex">
								<div></div>
								<div></div>
								<div></div>
							</div>
						</div>
						<div class="upsale__block__bot-right__sub-wrap dnone" style="display: block;">
							<div class="montage__content-wrap">
								<span class="montage__text">intro text 
								<div class="montage__floor-wrap montage__comp-wrap dflex">
									<div class="montage__floor dflex">
										<div class="floor__item-wrap">   //на этот блок должен работать click и включать/выключать дочерний второстепенный input
											<div class="floor__item-inner">
												<div class="floor__item">
													<input id="first_floor" type="checkbox" name="groundfloor" value="groundfloor">  //второстепенный input
													<div class="floor__item__img">
														<img src="" alt="">
													</div>
													<span class="floor__item__text">Ground floor</span>
												</div>
											</div>
										</div>      //закрытие блока .floor__item-wrap
										<div class="floor__item-wrap">   //на этот блок должен работать click и включать/выключать дочерний второстепенный input
											<div class="floor__item-inner">
												<div class="floor__item">
													<input id="sec_floor" type="checkbox" name="middlefloor" value="middlefloor">  //второстепенный input
													<div class="floor__item__img">
														<img src="" alt="">
													</div>
													<span class="floor__item__text">Second floor</span>
												</div>
											</div>
										</div>	//закрытие блока .floor__item-wrap
										<div class="floor__item-wrap">   //на этот блок должен работать click и включать/выключать дочерний второстепенный input
											<div class="floor__item-inner">
												<div class="floor__item">
													<input id="third_floor" type="checkbox" name="topfloor" value="topfloor">  //второстепенный input
													<div class="floor__item__img">
														<img src="" alt="">
													</div>
													<span class="floor__item__text">Third floor</span>
												</div>
											</div>
										</div>  //закрытие блока .floor__item-wrap
										<div class="floor__item-wrap">  //на этот блок должен работать click и включать/выключать дочерний второстепенный input
											<div class="floor__item-inner">
												<div class="floor__item">
													<input id="all_floor" type="checkbox" name="apartment" value="apartment"> //второстепенный input
													<div class="floor__item__img">
														<img src="" alt="">
													</div>
													<span class="floor__item__text">Apartment Building</span>
												</div>
											</div>
										</div>  //закрытие блока .floor__item-wrap
									</div>
								</div>
							</div>			
						</div>			
					</div>

laimas 16.10.2019 17:17

Охренеть. Чем в конце концов должен заниматься флажок id="floor":
а) только показывать/скрывать блок?
б) показывать/скрывать блок и выбирать все второстепенные флажки?

Aruta 16.10.2019 17:20

laimas,
Цитата:

Сообщение от laimas
Чем в конце концов должен заниматься флажок id="floor":

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

laimas 16.10.2019 18:05

Цитата:

Сообщение от Aruta
только отключать второстепенные флажки

То есть наоборот - выбор этого флажка, это сброс последующих, а выбрать им все последующие нельзя?

Блоков upsale__block__sub-right-wrap на этой странице всегда два?

Aruta 16.10.2019 18:26

Цитата:

Сообщение от laimas
То есть наоборот - выбор этого флажка, это сброс последующих, а выбрать им все последующие нельзя?

Верно

Цитата:

Сообщение от laimas
Блоков upsale__block__sub-right-wrap на этой странице всегда два?

Пока два, т.к. пока хардкод в этой части, но страница динамическая и когда запрограммирую php, то там может быть и более 7 таких блоков.
https://prnt.sc/pk5amz

laimas 16.10.2019 19:02

Ясно.Дело в том, что в первом блоке оказывается есть и другие поля, но типа file, а значит селектор для делегирования нельзя так указывать.

Aruta 16.10.2019 19:24

laimas,
первый блок не смотрите. Надо на примере второго только создать скрипт.
первый блок законченный уже. он такой один будет и его скрипты отдельные. Кроме скрипта show/hide для показа дочернего .upsale__block__bot-right__sub-wrap. Но и тот работает по принципу this.children()

laimas 16.10.2019 20:40

Цитата:

Сообщение от Aruta
Надо на примере второго только создать скрипт.

Думать надо головой, а не пятой точкой. ;) Поле типа file также имеет событие change, а делегирование по имени класса блоков. Что при этом произойдет при выборе файла в первом блоке?

Код этого обработчика $('.upsale__block__sub-right-wrap').on('click', '.upsale__block__bot-right__title-wrap', function() ... заменить на:
$('div.upsale__block__bot-right__title-wrap').click(function() {
        
        $(this).next()
               .slideToggle(100)
               .end()
               .find('img').toggleClass('arrow_down arrow-up')
               .end() 
               .find('.montage__more').hide()
               .end()
               .find('.invite').show();
        
                           
});

Здесь делегирование совсем не требуется. Правда зачем в нем строки:

$(this).siblings('.upsale__block__bot-right__sub-wrap').find('.montage__more').hide();
$(this).siblings('.upsale__block__bot-right__sub-wrap').find('.invite').show();

(в новом коде это четыре последних операции в цепочке) если можно сразу сделать нужно видимым/скрытым. Код обработки изменения флажков заменить на этот:
$('div.upsale__block__sub-right-wrap').slice(1).on('change', 'input', function(e) { 
	
    var a = $(e.delegateTarget).find('input'), chk = a.slice(1);
    
    if(a.eq(0)[0]==this) {
        chk.prop('checked', false);
        this.disabled = true;  
    }else {
        var c = chk.filter(':checked').length;
        a.eq(0).prop({checked: c, disabled: !c});   
    }
    
});

Он устанавливается на блоки кроме первого.

Aruta 17.10.2019 05:10

Вложений: 1
laimas,
Цитата:

Сообщение от laimas
Здесь делегирование совсем не требуется. Правда зачем в нем строки:

$(this).siblings('.upsale__block__bot-right__sub-wrap').find('.montage__more').hide();
$(this).siblings('.upsale__block__bot-right__sub-wrap').find('.invite').show();

это для первого блока, там есть 2 кнопки:

- при нажатии на .btn_more (желтая кнопка) скрывается кнопка (синяя) .invite и открывается появляется блок .montage__more. Когда повторно нажимаем на .btn_more, то montage__more скрывается, а кнокпа .invite (синяя) появляется на том месте где была скрыта. Причем кнопка .invite дублируется в блоке .montage__more, когда тот открывается, НО она не участвует в срипте show/hide (и не должна).

- если развернут блок .montage__more, то при нажатии на .upsale__block__bot-right__title-wrap этот блок должен свернуться и кнопка .invite должна стать show(), чтобы при последующем открытии она была доступна пользователю, т.к. если этого не сделать, то она не появится.

на картинках всё показал. Надеюсь понятно объясняю, а не только для меня мои мысли понятны:)

Но опять же это не решает проблему нажатия на .floor__item-wrap, чтобы сработал его дочерний чекбокс

laimas 17.10.2019 05:54

Цитата:

Сообщение от Aruta
Надеюсь понятно объясняю

Для меня нет. Родительский блок показывается/скрывается, в нем же '.montage__more' и '.invite', которым при любом состоянии родителя предписано одному всегда скрываться, другому показаться.

Цитата:

Сообщение от Aruta
Но опять же это не решает проблему нажатия на .floor__item-wrap, чтобы сработал его дочерний чекбокс

Вообще не понять что это и о чем.

Malleys 17.10.2019 06:24

Цитата:

Сообщение от Aruta
Но опять же это не решает проблему нажатия на .floor__item-wrap, чтобы сработал его дочерний чекбокс

Так замените <div> на <label>

Aruta 17.10.2019 07:01

Цитата:

Сообщение от Malleys
Так замените <div> на <label>

Malleys,
наверное так и сделаю. А то 2 дня уже страдаем, а до этого еще я сам 2 потратил.

laimas,
Спасибо за Ваше терпение и помощь!
Жаль нельзя плюсиков больше поставить - я вам вчера уже один поставил:)

laimas 17.10.2019 07:26

Цитата:

Сообщение от Aruta
наверное так и сделаю

Ранее надо было тогда вести речь о выборе не только по флажку, но и по родителю. Заменять div не обязательно, можно просто обернуть его дочерние элементы label. Если это затруднительно сделать, то можно это сделать программно при загрузке страницы, для этого добавить в цепочку установки обработчика флажков такую операцию, чтобы выглядело так:

$('div.upsale__block__sub-right-wrap').slice(1).on('change', 'input', function(e) { 

    var chk = $(e.delegateTarget).find('input');
    
    if(chk.eq(0)[0]==this) {
        chk.slice(1).prop('checked', false);
        this.disabled = true;  
    }else {
        var c = chk.slice(1).filter(':checked').length;
        chk.eq(0).prop({checked: c, disabled: !c});   
    }
    
}).find('.floor__item').each(function() {
    $(this).children().wrapAll('<label/>')
});

Aruta 17.10.2019 07:30

Заменил div на label и теперь новая задача возникает:

Раньше, когда галка ставилась для второстепенного input, то родительскому блоку добавлялся background цветом, а галка снималась - background белым делался.

Как теперь это добавить в тот код, что имеется?:)

$('div.upsale__block__sub-right-wrap').slice(1).on('change', 'input', function(e) { 
	
    var a = $(e.delegateTarget).find('input'), chk = a.slice(1);
    
    if(a.eq(0)[0]==this) {
        chk.prop('checked', false);
        this.disabled = true;  
    }else {
        var c = chk.filter(':checked').length;
        a.eq(0).prop({checked: c, disabled: !c});   
    }
    
});

laimas 17.10.2019 07:37

Цитата:

Сообщение от Aruta
Заменил div на label и теперь новая задача возникае

А выше посмотреть? Зачем менять div на label?

Aruta 17.10.2019 07:41

Цитата:

Сообщение от laimas
Ранее надо было тогда вести речь о выборе не только по флажку, но и по родителю

Я это писал:)

А вот про цвет не писал - думал сам справлюсь, но не понимаю как связать это с вашим кодом - не работает то, что я пробую.

Aruta 17.10.2019 07:42

laimas,
Цитата:

Сообщение от laimas
А выше посмотреть? Зачем менять div на label?

не видел, когда вы это писали. Обновилась страница позже уже:)

laimas 17.10.2019 07:46

Цитата:

Сообщение от Aruta
А вот про цвет не писал - думал сам справлюсь, но не понимаю как связать это с вашим кодом

Добавлять/удалять некий класс блоку floor__item, например active, который и будет раскрашивать, то есть:

.floor__item.active {
    background-color: #A5D8E4;
}


$('div.upsale__block__sub-right-wrap').slice(1).on('change', 'input', function(e) {
     
    var a = $(e.delegateTarget).find('input'), chk = a.slice(1);
     
    if(a.eq(0)[0]==this) {
        chk.prop('checked', false);
        this.disabled = true;
        $(e.delegateTarget).find('.floor__item').removeClass('active') 
    }else {
        var c = chk.filter(':checked').length;
        a.eq(0).prop({checked: c, disabled: !c});  
    }
    
    $(this).closest('.floor__item').toggleClass('active')
     
}).find('.floor__item').each(function() {
    $(this).children().wrapAll('<label/>')
});

laimas 17.10.2019 07:56

Кстати, код свернуть/развернуть надо тоже дополнить:

$('div.upsale__block__bot-right__title-wrap').click(function(e) {
        if(e.target.localName!='input') {
            $(this).next()
                   .slideToggle(100)
                   .end()
                   .find('img').toggleClass('arrow_down arrow-up')
                   .end() 
                   .find('.montage__more').hide()
                   .end()
                   .find('.invite').show();
        }
});


Иначе по флажку тоже будет сворачивать.

Aruta 17.10.2019 08:48

Цитата:

Сообщение от laimas (Сообщение 514151)
Добавлять/удалять некий класс блоку floor__item, например active, который и будет раскрашивать, то есть:

.floor__item.active {
    background-color: #A5D8E4;
}


$('div.upsale__block__sub-right-wrap').slice(1).on('change', 'input', function(e) {
     
    var a = $(e.delegateTarget).find('input'), chk = a.slice(1);
     
    if(a.eq(0)[0]==this) {
        chk.prop('checked', false);
        this.disabled = true;
        $(e.delegateTarget).find('.floor__item').removeClass('active') 
    }else {
        var c = chk.filter(':checked').length;
        a.eq(0).prop({checked: c, disabled: !c});  
    }
    
    $(this).closest('.floor__item').toggleClass('active')
     
}).find('.floor__item').each(function() {
    $(this).children().wrapAll('<label/>')
});

это я пробовал:)
И тут есть момент - closest() не поддерживается IE даже 10+, и при снятии главной галочки, второстепенные снимаются, а окраска с их блоков нет.
Подключать 2 полифила для closest() не очень хочется, поэтому я и решил переписать с JS на jQuery код, потому что компактней выходит:)

P.S. окрашивать надо не .floor__item, а .floor__item-wrap

laimas 17.10.2019 09:06

Цитата:

Сообщение от Aruta
И тут есть момент - closest() не поддерживается IE даже 10+

Используйте новую JQ.

Цитата:

Сообщение от Aruta
окрашивать надо не .floor__item, а .floor__item-wrap

Проблема, замените на него:

$('div.upsale__block__sub-right-wrap').slice(1).on('change', 'input', function(e) {
     
    var a = $(e.delegateTarget).find('input'), chk = a.slice(1);
     
    if(a.eq(0)[0]==this) {
        chk.prop('checked', false);
        this.disabled = true;
        $(e.delegateTarget).find('.floor__item-wrap').removeClass('active') 
    }else {
        var c = chk.filter(':checked').length;
        a.eq(0).prop({checked: c, disabled: !c});  
    }
    
    //$(this).closest('.floor__item-wrap').toggleClass('active')
    //а так для инвалидов
    $(this).parents('.floor__item-wrap').toggleClass('active')   
     
}).find('.floor__item-wrap > div').wrap('<label/>');

Aruta 17.10.2019 09:32

laimas,
Вы мой кумир:) Спасибо огромное! Это то что надо!:dance:

Правда IE всё равно не хочет работать с нажатием на блок, а не на input. Но зато другие работают - этого достаточно.

Тему скрипта можно закрывать, а тему благодарностей laimas открывать:thanks:

p.s.
Цитата:

Сообщение от laimas
Используйте новую JQ.

это IE его не знает - такой он допотопный до сих пор. Ему чтобы понимать closest(), надо полифилы вставлять для matches и closest

Malleys 17.10.2019 09:33

Цитата:

Сообщение от laimas
(a.eq(0)[0]==this

Красотища! А говорят, jQuery разработку упрощает!

Aruta, два дня не копался, наверное надо давать понятные имена, а то можно легко запутаться с вашим кодом и всё не понимать, что такое там написано!

Вам такое почему-то запрещено писать? Я имею в виду про то, что вы печатаете много <div>, и ещё обёртки и ещё обёртки...
<details class="upsale_sub_right">
	<summary>
		<input type="checkbox">
		Choose your floor
	</summary>

	<p class="montage_text">intro text</p>
	<div class="floor_items">
		<label>
			<input type="checkbox" name="groundfloor">
			<span class="floor_item_text">Ground floor</span>
		</label>
		<label>
			<input type="checkbox" name="middlefloor">
			<span class="floor_item_text">Second floor</span>
		</label>
		<label>
			<input type="checkbox" name="topfloor">
			<span class="floor_item_text">Third floor</span>
		</label>
		<label>
			<input type="checkbox" name="apartment">
			<span class="floor_item_text">Apartment Building</span>
		</label>
	</div>
</details>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>

$(".upsale_sub_right").on("change", function(event) {
	var inputs = $(this).find("input:not(summary input)");
	var parentInput = $(this).find("summary input");

	if(parentInput.is(event.target)) {
		inputs.prop("checked", parentInput.prop("checked"));
	} else {
		var checkedInputs = inputs.filter(":checked");
		parentInput.prop({
			checked: checkedInputs.length !== 0,
			indeterminate:
				checkedInputs.length !== 0 &&
				inputs.length !== checkedInputs.length
		});
	}

	$(this)
		.find(".floor_items > label.active:has(:not(:checked))").removeClass("active")
		.end()
		.find(".floor_items > label:has(:checked)").addClass("active")
	;
});

</script>

<style>

.floor_items > label {
	display: block;
}

.floor_items > .active {
	background-color: #A5D8E4;
}

</style>

Aruta 17.10.2019 09:39

Хотел сделать финальный вариант, чтобы другие сразу могли его увидеть, но он не работает тут как надо - проще файлами прикладывать:)

laimas 17.10.2019 10:00

Цитата:

Сообщение от Aruta
это IE его не знает - такой он допотопный до сих пор.

Это разработчики JQ плюнули на старых ишаков, последняя версия которая поддерживает IE8, это 1.8. Сколько можно в старье копаться, вы хотя бы знаете сколько на вашем ресурсе пользователей IE8 и прочего старья?

Aruta 17.10.2019 10:13

laimas,
этот сайт еще даже не запущен:( Желание заказчика, чтобы работало везде более менее одинаково - вот и кручусь.
Сайт мне достался в том виде, в котором есть сейчас.

Моих доработок там только пара страниц всего, включая backend для них.

Вот теперь могу спокойно приниматься за back для этой страницы.

А по поводу поддержки closest(), я знаю что в JS closest и IE не дружат. И тут я думал тоже такая же зависимость причина-следствие сохраняется:)

Спасибо за пояснение!

laimas 17.10.2019 10:47

Цитата:

Сообщение от Aruta
А по поводу поддержки closest(), я знаю что в JS closest и IE не дружат.

В ОС у меня IE11, и работает эта функция без проблем, и при включении эмуляции 10, 9 тоже. Более старое у меня есть в гостевой ОС, но не охота ради проверки старья все это запускать и радоваться или огорчаться. Ну нет, так нет. )

Aruta 17.10.2019 11:27

laimas,
Теперь вы путаете:) О jQuery не говорю, только о чистом JS.

https://caniuse.com/#search=closest

laimas 17.10.2019 11:31

Цитата:

Сообщение от Aruta
Теперь вы путаете О jQuery не говорю, только о чистом JS

А где тут нативный JS?

$(this).closest('.floor__item-wrap').toggleClass('active')

Aruta 17.10.2019 12:56

laimas,
Цитата:

Сообщение от Aruta
А по поводу поддержки closest(), я знаю что в JS closest и IE не дружат. И тут я думал тоже такая же зависимость причина-следствие сохраняется

Я сначала говорил о jQuery, потом вы о нём рассказали. А ссылка на canIUse - про JS и IE и поддержку closest().

Короче, не задумывайтесь об этом:) не стоит оно того - только время в пустую.


Часовой пояс GMT +3, время: 07:35.