Включить/отключить checkbox при включении нескольких других checkbox
Добрый день!
Задача тут встала передо мной на jQuery... часть её решения нашел, но вот над этой частью бьюсь и не получается никак. Ссылка на вид страницы: http://prntscr.com/pjfpdb Нужно чтобы: - чекбокс id="floor" получал галочку, когда хотя бы один из один из дочерних чекбоксов в <div class="floor__item"> имеет галочку и наоборот, если галочки снять со всех дочерних чекбоксов <div class="floor__item">, то и на id="floor" галочка убиралась (но она должна быть пока имеется хоть один включенный флаг). - если с id="floor" снять галочку, то и со всех дочерних чекбоксов <div class="floor__item"> тоже снималась. - если ни на одном дочернем чекбоксе <div class="floor__item"> нет, то id="floor" не кликабелен. Весь код jQuery должен быть написан не от id, а по дочка/родитель, т.к. подобный код в других частях страницы планируется использовать. ниже код html только с одним из 4-х блоков, которые содержат чекбокс, который нужно прослушивать, т.к. остальные 3 блока отличаются только картинкой и подписью под ней. onclick="event.stopPropagation()" для id="floor" сделан, чтобы при раскрытии дочернего блока id="floor" не отмечался, т.к. блок ниже строки "Choose your floor" открывается по нажатию на родителя id="floor" <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()"/> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain </span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input id="first_floor" type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text"><?php echo $this->language->get('text_floor_0'); ?></span> </div> </div> </div> </div> </div> </div> </div> </div> У меня уже есть код, который активирует чекбоксы в блоках <div class="floor__item"> - с ним я справился за 3 часа, т.к. новенький в этом деле:) может пригодится при рассмотрении моего вопроса:) $('.montage__floor').on('click', '.floor__item-wrap', function() { var $input = $(this).children('.floor__item-inner').children('.floor__item').children('input'); if ($input.prop('checked')) { $input.prop('checked',false); $(this).css('background', 'none'); }else{ $input.prop('checked',true); $(this).css('background', '#bbd9ff'); }; }); |
Aruta, как вариант...
<!DOCTYPE html> <html> <head> <meta http-equiv='Content-Type' content='text/html; charset=windows-1251' /> <script src='https://code.jquery.com/jquery-latest.js'></script> <!-- <script src="https://code.angularjs.org/1.3.9/angular.min.js"></script> <script src="https://code.angularjs.org/1.3.9/angular-route.js"></script> --> <style type='text/css'> </style> <script type='text/javascript'> $(function(){ $('.upsale__block__sub-right-wrap :checkbox').click(function(){ if (this.id=='floor') { this.checked=false; this.disabled=true; $(this).parents('.upsale__block__sub-right-wrap').find('.floor__item :checkbox').prop('checked',false); return; }; if (this.name=='groundfloor') { if (this.checked) { $('#floor').prop({ 'disabled': false, 'checked': true }); return; }; var o=$(this).parents('.upsale__block__sub-right-wrap').find('.floor__item :checked'); if (o.length==0) { $('#floor').prop({ 'disabled': true, 'checked': false }); }; }; }); }); </script> </head> <body> <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" /> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain </span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 0</span> </div> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 1</span> </div> </div> </div> </div> </div> </div> </div> </div> </body> </html> |
Цитата:
В событии изменения (change, а не click) для дочерних флажков нужно брать по фильтру выбранные, и значение length таковых указывать в .prop('checked') для общего флажка. Ну а изменение общего флажка это вообще просто, его состояние флажкам ниже. |
ksa,
на форуме работает вроде как-то, но в живой проект когда добавил, то вышло, что при выборе нижних чекбоксов верхний не отмечается - как и сейчас у меня, а если вручную ставить галку верхнему, то при снятии он неактивен становится пока не нажмешь f5. Нашел где исправить чтобы disabled не был input верхним, но всё же это завязано на id, а не на родителей/дочек... |
laimas, если .floor__item-inner не добавить, то он вообще не ставит галочку - не спускается по dom куда надо
|
Цитата:
В моем варианте все завязано на ту структуру которая есть в примере. Если по факту она не такая - можно просто изменить "родительский" селектор. ;) |
<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" /> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain </span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 0</span> </div> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 1</span> </div> </div> </div> </div> </div> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $('div.upsale__block__sub-right-wrap').on('change', 'input', function(e) { var chk = $(e.delegateTarget).find('input'); if(chk.eq(0)[0]==this) chk.slice(1).prop('checked', this.checked); else chk.eq(0).prop('checked', chk.slice(1).filter(':checked').length); }) </script> |
laimas,
да вроде тот. Вот вообще весь код без обрезания:) <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()"/> <span> <img class="arrow arrow_down" src="http://test.vhost78896.cpsite.ru/catalog/view/theme/myown/image/arrowselect.png" alt="arrow_down"/> Choose your floor </span> </div> <div class="col-title__price-wrap dflex"> <div class="col-title__quantity-header col-width">Aantal</div> <div class="col-title__price col-width" style="white-space:nowrap;">Prijs</div> <div class="col-title__total col-title__totalheader col-width">Totaal</div> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain</span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input id="first_floor" type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text"><?php echo $this->language->get('text_floor_1'); ?></span> </div> </div> </div> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input id="sec_floor" type="checkbox" name="middlefloor" value="middlefloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/middleFloor.svg" alt=""> </div> <span class="floor__item__text"><?php echo $this->language->get('text_floor_2'); ?></span> </div> </div> </div> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input id="third_floor" type="checkbox" name="topfloor" value="topfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/topFloor.svg" alt=""> </div> <span class="floor__item__text"><?php echo $this->language->get('text_floor_3'); ?></span> </div> </div> </div> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input id="all_floor" type="checkbox" name="apartment" value="apartment"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/apartmentBuilding.svg" alt=""> </div> <span class="floor__item__text"><?php echo $this->language->get('text_floor_build'); ?></span> </div> </div> </div> </div> </div> </div> </div> </div> |
laimas,
как тут добавить исполняемый код как у вас в посте? Я закину в него всё - css, js, html, чтобы можно было видеть как это всё работает сейчас |
Цитата:
Странно, если его сделать недоступным, то выбрать все им можно только в случае когда хотя бы "один из" был выбран. Что так и должно быть? |
Цитата:
|
laimas,
Цитата:
Там еще и php потом писать, так я вообще даже не понимаю как эти связи будут создаваться. "Сис. админ был творческой личностью, поэтому все провода уложил узелком и паутинкой" - вот такой код будет:( |
Ну как это понимать в контексте кнопки "Выбрать все"?
<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" disabled /> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain </span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 0</span> </div> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 1</span> </div> </div> </div> </div> </div> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $('div.upsale__block__sub-right-wrap').on('change', 'input', function(e) { var chk = $(e.delegateTarget).find('input'); if(chk.eq(0)[0]==this) chk.slice(1).prop('checked', this.checked); else { var c = chk.slice(1).filter(':checked').length; chk.eq(0).prop({checked: c, disabled: !c}); } }) </script> Где логика в работе этого флажка? |
laimas,
Спасибо. Кода много вставлять получается сюда... Проще дать ссылку - http://test.vhost78896.cpsite.ru/ В футере есть webshop - переходите туда. Потом первый товар можно тыкнуть и после этого (на картинке) - https://prnt.sc/pjl18z После этого окажитесь в корзине и увидите блок, который я пытаюсь править. Все скрипты, которые в этом блоке я написал: $(document).ready(function() { $('.montage__comp-wrap').on('click', '.btn_more', function() { $(this).parents('.company__btn').parents('.company__btn-wrap').parents('.montage__company-wrap').siblings('.montage__more').slideToggle(100); $(this).parents('.company__btn').siblings('.company__btn').children('.invite').slideToggle(0); }); // Show/Hide montage companies $('.upsale__block__sub-right-wrap').on('click', '.upsale__block__bot-right__title-wrap', function() { $(this).siblings('.upsale__block__bot-right__sub-wrap').slideToggle(100); var $arrow = $(this).children('.upsale__block__bot-right__title').find('img'); if( $arrow.hasClass('arrow_down')) { $arrow.removeClass('arrow_down'); $arrow.addClass('arrow-up'); } else { $arrow.removeClass('arrow-up'); $arrow.addClass('arrow_down'); } $(this).siblings('.upsale__block__bot-right__sub-wrap').find('.montage__more').hide(); $(this).siblings('.upsale__block__bot-right__sub-wrap').find('.invite').show(); }); //Choose checkbox when clicked on his parrent $('.montage__floor').on('click', '.floor__item-wrap', function() { var $input = $(this).children('.floor__item-inner').find('input'); if ($input.prop('checked')) { $input.prop('checked',false); $(this).css('background', 'none'); }else{ $input.prop('checked',true); $(this).css('background', '#bbd9ff'); }; }); }); Первый скрипт можно не рассматривать - он скрывает кнопку, которой нет в нужном блоке, а вот второй скрипт - открывается слайдер с блоками с чекбоксами. третий - вкл/выкл чекбокс при нажатии на родительский блок |
Не понял причем тут флажки и картинка. Впрочем, как душе угодно, делайте так как желается. )
|
laimas,
на картинке я показал как попасть на сайте в корзину со страницы товара всего лишь:) |
Цитата:
|
laimas,
там наглядно в devtools можно посмотреть как блоки расположены и как в целом это выглядит. Потому что я не понимаю, почему на форуме работает, а на сайте нет. Я даже попробовал модифицировать, но не вышло |
Цитата:
|
laimas,
предложенный вами вариант |
Значит есть ошибки, нужно заглянуть в отладчик, что он вещает.
Собственно ничего сложного нет, нужно удалить ваши обработчики флажков и добавить что я написал, а работа его проста: //общему родителю флажков делегируется обработка изменения их состояния //если таких блоков upsale__block__sub-right-wrap много, то этот обработчик будет выполнятся только в контексте текущего $('div.upsale__block__sub-right-wrap').on('change', 'input', function(e) { var chk = $(e.delegateTarget).find('input'); //получили все флажки текущего родителя //если источник события это флажок block__check, что можно проверить и так: $(this).hasClass('block__check') if(chk.eq(0)[0]==this) chk.slice(1).prop('checked', this.checked); //то определить его состояние всем последующим флажкам текущего родителя else { //иначе это изменение флажков набора var c = chk.slice(1).filter(':checked').length; //есть ли выбранные флажки в наборе? chk.eq(0).prop({checked: c, disabled: !c}); //результат операции присвоить свойствам checked и disabled флажка block__check } }); |
laimas,
Если я отключаю свои обработчики, тогда ваш код включает и выключает все блоки разом, а задача другая: Цитата:
Чего не хватает в вашем коде, так это 1 пункта и 3 пункта:) |
Цитата:
<div class="upsale__block__sub-right-wrap"> <h3>Block 1</h3> <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" disabled="" /> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain </span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 0</span> </div> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 1</span> </div> </div> </div> </div> </div> </div> </div> </div> <div class="upsale__block__sub-right-wrap"> <h3>Block 2</h3> <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" disabled="" /> </div> </div> <div class="upsale__block__bot-right__sub-wrap dnone"> <div class="montage__content-wrap"> <span class="montage__text">intro text where we explain </span> <div class="montage__floor-wrap montage__comp-wrap dflex"> <div class="montage__floor dflex"> <div class="floor__item-wrap"> <div class="floor__item-inner"> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 0</span> </div> <div class="floor__item"> <input type="checkbox" name="groundfloor" value="groundfloor"> <div class="floor__item__img"> <img src="catalog/view/theme/myown/image/floor/groundFloor.svg" alt=""> </div> <span class="floor__item__text">floor__item__text 1</span> </div> </div> </div> </div> </div> </div> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $('div.upsale__block__sub-right-wrap').on('change', 'input', function(e) { var chk = $(e.delegateTarget).find('input'), set = chk.slice(1); if(chk.eq(0)[0]==this) set.prop('checked', this.checked); else { var c = set.filter(':checked').length; chk.eq(0).prop({checked: c, disabled: !c}); } }) </script> Флажки выбираются только в своих блоках или в обоих не зависимо в каком блоке выбор или же только в своем? |
laimas,
Цитата:
|
Цитата:
|
laimas,
да, не верная. Выходит что при нажатии на главный чекбокс выбираются все нижние, но при выборе нижнего (если жать именно любой из нижних) не отмечается главный. главный приходится вручную отмечать Надо чтобы нажал даже если один из нижнихвыбран, то главный тоже имел галку. А сейчас такого нет. Но зато работает, что если снять галку с главног, то и с дочек снимается - это хорошо и должно быть |
Цитата:
Цитата:
|
|
Здесь, в песочнице, запустите код что я выставил. Верно все? А у вас не так может быть потому, если: а) либо верстка не такая и значит селектор надо изменить, б) либо есть ошибки в коде и надо в отладчике все проверить.
|
laimas,
нет ошибок в коде:( не ругается ни на что по поводу верстки я специально дал вам ссылку и инструкцию, чтобы посмотреть на живом примере как это работает |
Цитата:
Вот что я вижу, и если просмотреть код этих флажков, то там и близко нет той верстки о которой тут речь. Где, в каком месте эти блоки с флажками, бог его знает. |
laimas,
не туда смотрите... После этой страницы надо перейти в корзину - внизу большая желтая кнопка. И вот тогда уже вы попадёте на нужную страницу и там будет то что я пытаюсь сделать. Спасибо за попытку помочь, всё равно http://prntscr.com/pjv28w |
Во-первых удалить ошибки, которые у вас есть - это касаемо метода live(), $.browser и т.п., которые устарели и удалены в новых версиях JQ. В новых версиях метод live() заменяет метод on().
У вас подключается давно убитая версия 1.7.1, в ней нет метода on(), поэтому мой скрипт и не работает. А у вас ошибки связанные с методом live() означают значит проблемы с доступом к объектам. Решение (варианты): а) упорно паритесь со старьем, заменяете то, что вам предлагают, на старые методы; б) выбрасываете в помойку старье, подключаете новую версию JQ (и плагины под нее), подправляя в коде проблемные места, и больше никогда не ломать голову по этому поводу - все что вам тут будут предлагать уж точно не будут писать под давно умершую версию библиотеки. |
laimas,
Спасибо. Сейчас проверю про версии. В таком состоянии мне его передали, а переписывать всё с нуля нет желания:) |
laimas,
странно, но метод on() поддерживается 1.7 ведь все мои скрипты на нём я писал. Нашел я проблему! заработало, но только если жать на чекбокс, а не на его родителя. А я то постоянно жал по задумке - на родительский блок этажа, поэтому и думал, что не работает:) Теперь встала проблема новая тогда - нужно жать на родительский блок, а не на сам input чтобы чекбокс у каждого блока этажа принимал on/off |
Цитата:
$('.montage__floor').on('click', '.floor__item-wrap', function() { var $input = $(this).children('.floor__item-inner').find('input'); if ($input.prop('checked')) { $input.prop('checked',false); $(this).css('background', 'none'); }else{ $input.prop('checked',true); $(this).css('background', '#bbd9ff'); }; }); А он не должен затрагивать иные флажки, то есть нужно либо разделить события пространством имен, либо конкретизиравать селектор. И еще, если этот обработчик убрать, то флажки даже естественным образом (без обработчиков) нельзя выбрать, а это говорит о том, что в коде есть нечто, что мешает корректной работе. И эта ошибка на сервере была замечена - Warning: getimagesize( http://test.vhost78896.cpsite.ru/ima...ast-raam.png): failed to open stream: No such file or directory in /home/u78896/test.vhost78896.cpsite.ru/vqmod/vqcache/vq2-catalog_controller_checkout_cart.php on line 465. |
laimas,
Ваш код работает полностью если удалить мой $('.montage__floor').on('click', '.floor__item-wrap', function() { var $input = $(this).children('.floor__item-inner').find('input'); if ($input.prop('checked')) { $input.prop('checked',false); $(this).css('background', 'none'); }else{ $input.prop('checked',true); $(this).css('background', '#bbd9ff'); }; }); Все input выделяются без проблем, но тогда надо жать на сам input. Залил изменения на сервер. Сейчас там только ваш код //общему родителю флажков делегируется обработка изменения их состояния //если таких блоков upsale__block__sub-right-wrap много, то этот обработчик будет выполнятся только в контексте текущего $('div.upsale__block__sub-right-wrap').on('change', 'input', function(e) { var chk = $(e.delegateTarget).find('input'); //получили все флажки текущего родителя //если источник события это флажок block__check, что можно проверить и так: $(this).hasClass('block__check') if(chk.eq(0)[0]==this) chk.slice(1).prop('checked', this.checked); //то определить его состояние всем последующим флажкам текущего родителя else { //иначе это изменение флажков набора var c = chk.slice(1).filter(':checked').length; //есть ли выбранные флажки в наборе? chk.eq(0).prop({checked: c, disabled: !c}); //результат операции присвоить свойствам checked и disabled флажка block__check } }); |
Не работает обработчик события chage (поместите в обработчик вывод в консоль или alert, для того чтобы убедится в этом), и зачем на все флажки этих блоков навешан обработчик click? Судя по логике вот это $('.montage__floor').on('click', '.floor__item-wrap', function() должно быть только для флажка "Все".
И удалите ошибку на сервере. Откройте свою страницу в FF, в отладчике в инспекторе кода можно видеть обработчики каких событий имеет элемент. Если есть такие, то у элемента будет кнопка "event", щелчок по которой покажет все навешанные на него обработчики. Анализируйте для чего вы навешали лишнего. |
laimas,
погиб хостинг видать:) час уже не может обновить файлы, которые я залил. Нет на этих чекбоксах event. http://prntscr.com/pjwozb на локальном сервер проверил - обработчик срабатывает каждый раз, когда я жму на любой из чекбоксов |
Цитата:
|
Часовой пояс GMT +3, время: 04:53. |