Найти в родителе элемент с заданным классом
Добрый день.
Бьюсь на следующей задачей: структура хтмл такая: <h3 class="hide-next">1</h3> <div> <h4 class="hide-next">2</h4> <div> <h5 class="hide-next">3</h5> <div> </div> </div> </div> и так далее. так вот, мне нужно при клике на элементе hide-next найти всех его предков hide-next`ов. и их значение поместить в хэш-тэг страницы, чтобы при клике на самый нижний заголов в адресе получилось http://***.ru#1/2/3 получается пока что-то такое: $('.hide-next').click(function() { $(this).parents() .map(function () { return this.prev().text; }) .get().join("/"); window.location.hash = parentEls; }); я толкьо начинаю изучать jquery, абсолютно не понимаю, что в этом коде не так, в переменную ничего не записывается |
Круто! Даже в доку посмотрел. Только не туда посмотрел: там пример ниже показывает, что можно в parents селектор задавать:
.parents(".hide-next") |
.map(function () { return $(this).text(); }) |
$('.hide-next').click(function() { var parentEls = $(this).parents('.hide-next') .map(function () { return $(this).text(); }) .get().join("/"); window.location.hash = parentEls; }); переменная пустая, в хэш тэг ничего не записывается :( то ли поиск не производится, то ли надо чуть другим путём идти. первоначально идея была такая, найти предка и для каждого предка вернуть содержимое предыдущего элемента. |
$('.hide-next').click(function() { var parentEls = $(this).parents('.hide-next') .map(function () { return $(this).text(); }) .get().join("/"); console.info(parentEls); //window.location.hash = parentEls; }); вот такой код выводит в консоль пустые строчки. |
может быть это из-за того, что .hide-next не является родителем нашего элемента, по которому кликнули?
|
$('.hide-next').click(function() { var parentEls = $(this).parents("div").children('.hide-next') .map(function () { return $(this).text(); }) .get().join("/"); console.info(parentEls); //window.location.hash = parentEls; }); |
о, так работает. только это не до конца решает задачу. дело в том, что в одном диве может быть много элементов hide-next, кроме того, при клике на них висит функция, которая добавляет класс эктив и разворачивает следующий за ним элемент. конкретная задача — «запомнить весь путь до интересующего нас хайдера»
|
<h3 class="hide-next">1</h3> <div> <p>111</p> <h4 class="hide-next">11</h4> <div> <p>12123</p> <h5 class="hide-next">asda</h5> <ul> <li>a</li> <li>b</li> </ul> </div> <h4 class="hide-next">22</h4> <p>12123</p> </div> <h3 class="hide-next">2</h3> <div> <p>12123</p> <h5 class="hide-next">asda</h5> <div> <span class="hide-next">111</span> <p>123123</p> </div> </div> <h3 class="hide-next">3</h3> <div> <p>12123</p> <h5 class="hide-next">asda</h5> <ul> <li>a</li> <li>b</li> </ul> </div> вот в это констукции по клику на хайдер внутри верхнего дива (по одному из двух) функция вернет значения обоих. если сделать проверку по классу "active", который навесится после клика, тоже может вернутся оба значения, если пользователь до этого открывал предыдущий. т.е. мою задачу по созданию ссылки на конкретный хайдер это не решает |
$('.hide-next').click(function() { var parentEls = $(this).parents("div").prev('.hide-next') .map(function () { return $(this).text(); }) .get().join("/"); console.info(parentEls); //window.location.hash = parentEls; }); |
огромное спасибо вам!
а я поленился прочитать документацию к prev, думал неьлзя в него селектор передавать :( |
ну вот, дальше — хуже.
код чуть изменил, чтобы слэш не прыгал, добавил простенькое условие: $('.hide-next').click(function() { var parentEls = $(this).parents("div").prev('.hide-next') .map(function () { return $(this).text(); }) .get().join("/"); if(parentEls == "") { parentEls = $(this).text(); } else { parentEls = parentEls+"/"+$(this).text(); } window.location.hash = parentEls; }); но теперь мне нужно по сформировавшейся ссылке открыть все эти элементы. получается что-то вроде var hash = decodeURIComponent(location.hash.substring(1)); var hashEls = hash.split("/"); if($("*").find(".hide-next:contains("+hashEls[0]+")").trigger("click")) { for(var num = 1;num<hashEls.length;num++) { $("*").find(".hide-next:contains("+hashEls[num]+")").trigger("click"); } } но это не совсем то опять что нужно, потому что contains ищет просто совпадение и в итоге разворачивает всё, что только можно. скажите, пожалуйста, как лучше реализовать поиск в этом случае? нужно, чтобы только «те» элементы открывались, т.е. элементы с одинаковым text() могу встречаться на одной странице. я так понимаю, надо как-то связывать с иерархией, ориентироваться на предков и детей. но то ли конец дня, а скорее полная безрамотность в jquery не позволяют додумать код. |
$(".hide-next").each(function(){ var $self = $(this); if ( $.inArray( $self.text(), hashEls ) > -1 ) { $self.click(); } }) |
а каким образом можно исключить дублирования кликов? дело в том, что значения этих элементов могут совпадать. уникальным является только первый, самый верхний элемент и сам путь.
есть предположение, что можно в самом-самом верхнем диве найти первый хайдер, затем в его чилдрен второй и т.д. |
tadjik1, тогда остается только такой алгоритм
|
var hash = decodeURIComponent(location.hash.substring(1)); var hashEls = hash.split("/"); $(".hide-next").each(function(){ var $self = $(this); if ($self.text() == hashEls[0]) { $self.click(); } $self.children('.hide-next').each(function() { var lll = $(this); if ( $.inArray( $lll.text(), hashEls ) > -1 ) { $self.click(); } }) }); |
а, нет, не так. это не его дети, а соседские)
|
function openHider () { var hash = decodeURIComponent(location.hash.substring(1)); var hashEls = hash.split("/"); $(".hide-next").each(function(){ var $self = $(this); if ($self.text() == hashEls[0]) { $self.click(); hashEls = hashEls.splice(0,1); var child = $self.next().children(); openNextHiders(hashEls, child); } }); } function openNextHiders(hashElss, childs) { childs.find('.hide-next').each(function() { var $self = $(this); if ($self.text() == hashElss[0]) { $self.click(); hashElss = hashElss.splice(0,1); childs = $self.next().children(); openNextHiders(hashElss, childs); } }); } проблема в том, что массив стирается полностью в первой функции, не только 0-вой элемент. подскажите, пожалуйста, в каком месте нарушена логика? |
var hashEls = decodeURIComponent( location.hash.replace( /^#/, "" ) ).split("/"); function clickByHideElems( elems, k) { var $children = $(elems).children(); var $hideNext = $children.filter(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); if ( $hideNext.length ) { $hideNext.click(); if ( k < hashEls.length - 1 ) { clickByHideElems($hideNext.next("div"), k++); } } else { clickByHideElems( $children, k ); } } clickByHideElems( document.body, 0 ); |
не могу понять, в чем ошибка, но кликает только по первому элементу..
кстати, в document.body filter() не работает, там приходится через файнд() искать, дальше уже через фильтер. но факт остаётся фактом — кликт только по первому элементу. смотрю в консоли хрома переменная объявилась правильно, она глобальная. |
и для чего вот это условие:
else { clickByHideElems( $children, k ); } |
function clickByHideElems( elems, k ) { $children = $(elems).children(); if( k == 0 ) { $hideNext = $children.find(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); } else { $hideNext = $children.filter(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); } if ($hideNext.length) { $hideNext.click(); console.info(k); if ( k < hashEls.length - 1 ) { k = k+1; clickByHideElems($hideNext.next("div"), k); } } else { clickByHideElems( $children, k ); } } вот в таком виде вроде бы работает. спасибо!!! |
только всё равно поясните, пожалуйста, для чего последний else?
|
это в том случае сработает, когда хайдер не в верхнем диве?
|
код в else сработает, когда будет нулевая длина $hideNext
т.е. если этот код ничего не найдет if( k == 0 ) { $hideNext = $children.find(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); } else { $hideNext = $children.filter(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); } |
ок, спасибо всем большое за помощь. отдельный респект Никите. код итоговой функции:
function clickByHideElems( elems, k ) { $children = $(elems).children(); if( k == 0 ) { $hideNext = $children.find(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); } else { $hideNext = $children.filter(".hide-next").filter(function(){ return $(this).text() === hashEls[k]; }); } if ($hideNext.length) { $hideNext.click(); if ( k < hashEls.length - 1 ) { k = k+1; clickByHideElems($hideNext.next("div"), k); } else { destination = $hideNext.offset().top; $('html,body').animate({ scrollTop: destination }, 1000); } } else { clickByHideElems( $children, k ); } } |
не поверите, но это оказалось еще не всё. есть такая проблема: при нажатии на кнопку «назад» браузера происходит переход на прошлую страницу, а надо бы просто отменять последний открытый хайдер. подскажите, пожалуйста, каким образом это реализовать?
|
History API. Правда поддержка браузерами минимальная пока.
|
ну мне как раз нужна полная поддержка))
есть идея сделать через hashchange и onhashchange (IE). только я не знаю каким образом отличить изменение хэша при нажатии на «назад» от изменения при клике. |
Проверять location.hash через setTimeout или setInterval.
|
Часовой пояс GMT +3, время: 23:44. |