I have the <ul> tag as below. When clicked on the anchor link it should display a div with the ul list items underneath. On the click function of anchor tag, I need to get the complete height of the div (in fact the height of the ul with li items), the submenu
<ul>
<li>
<a></a>
<div>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</li>
</ul>
The html code is as below:
<ul class="menu level-1 plain" id="header-menu">
#{
var i = 1; //Used for submenu ID
}
#foreach (var menuItem in Model.Header.TopLevelNavigation)
{
if (i < 6)
{
<li #Html.Raw(i > Model.MenuMidPoint ? "class=\"sub-menu-nudge-left\"" : "")>
#if (menuItem.ContentLink.HasChildPages())
{
<a href="#sub-menu-#i" class="menu-link js-ui-header-all-menu-drill-down" aria-haspopup="true">
<span class="icon icon-chevron-left #Model.GetBoxIcon(i)"></span>
<span>#menuItem.Name</span>
</a>
<div id="sub-menu-#i" class="sub-menu" aria-label="submenu" aria-hidden="true">
#Html.DisplayEnumerableIContent("<ul class=\"level-2 plain\">{0}</ul>", "<li>{0}</li>", "menu-link", menuItem.ContentLink.GetChildPages(true, true))
</div>
}
</li>
}
i++;
}
</ul>
I tried the jquery function as below:
I tried as below, but I am unable to get the height of the submenu. It never gets into the foreach loop at all. Could anyone please help
$(".menu-link").click(function () {
var $subnavdev = $(this).parent().sublings('sub-menu').siblings('level-2 plain')
var totalHeight = 0;
$subnavdev.find('li').each(function() {
totalHeight += $(this).outerHeight(true);
});
alert(totalHeight);
});
Some of your class selectors were not specified correctly, plus there was a typographical error (all on Line 2).
Update - It also seems the siblings() methods may not be behaving as you intend them to... - And I got the .level-2 selector wrong still - since you need another . before plain. (See below example)
By using the closest() method you can go up to the nearest parent (for example, <li>), then use find() to pick out all .level-2.plain items nested within that parent.
Remember that your $(this) inside the handler function refers to the handled element, (in this case the .menu-link item being clicked.
$(".menu-link").click(function () {
var $subnavdev = $(this).closest('li').find('.level-2.plain');
// ...
});
Related
I have a list of tabs set up like this. All tabs have a class tab_<number> and the active tab also has an extra class tab_active
Below these tabs there is a div that shows the dynamic content based on which tab is active
<div class="tab_content">xxx</div>
What I'm trying to do is insert the div tab_content below the active tab.
This works, but only on the second click on the tab, which I don't understand why.
The second script I tried, was looping through the different tabs and trying to insert the div like this, but this only works on the last item, because it just loops through it.
/*
// I tried two solutions, this was my first
jQuery(".tabs li").click(function() {
jQuery(".tab_content").insertAfter(jQuery(".tab_active"));
});
*/
// second
var i;
for (i = 0; i < jQuery('.tabs li').length - 1; i++) {
jQuery(".tab_" + i).click(function() {
jQuery(".tab_content").insertAfter(jQuery(".tab_" + i));
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="tabs">
<li class="tab_0 tab_active">1</li>
<li class="tab_1">2</li>
<li class="tab_2">3</li>
<li class="tab_3">4</li>
<li class="tab_4">5</li>
</ul>
<div class="tab_content">xxx</div>
Can you guys/gals see what I'm doing wrong?
Much appreciated!
this can be done in something like following way.
Note though that if there are more tab_* elements in page then update the selector to be more stricter as needed to prevent selecting unexpected element.
$("[class^=tab_]").click(function(){
$(this).append($(".tab_content"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="tabs">
<li class="tab_0 tab_active">1</li>
<li class="tab_1">2</li>
<li class="tab_2">3</li>
<li class="tab_3">4</li>
<li class="tab_4">5</li>
</ul>
<div class="tab_content">xxx</div>
After scrolling down, it's applying only the home button.
Here is my code.
<ul class="mainmenu nav sf-menu" style="float: right;">
<li class="active" id="scrl-li">
<span>Home</span>
</li>
<li id="scrl-li">
<a href="about.html" ><span>About Us</span></a>
</li>
<li id="scrl-li">
<a href="about.html" ><span>Services</span></a>
</li>
</ul>
JavaScript code:
$(document).ready(function() {
var scrollTop = 0;
$(window).scroll(function() {
scrollTop = $(window).scrollTop();
$('.counter').html(scrollTop);
if (scrollTop >= 100) {
$("#scrl-li").css("marginTop","-20px");
} else if (scrollTop < 100) {
$("#scrl-li").css("marginTop","0px");
}
});
});
The other posters are correct that you should only have one of an ID per page, but you may still be able to work around the problem if you do not have control of the markup by using
$("[id='scrl-li']") to target the elements instead of $("#scrl-li").
Id's should be unique and not repeated across elements. Changing your id's to classes makes this code work:
Change the jquery id references as well as the html id references to classes
<li id="scrl-li">
to...
<li class="scrl-li">
and....
$("#scrl-li")
to...
$(".scrl-li")
jsfiddle: https://jsfiddle.net/xpvt214o/794901/
View the html code as you scroll and you will see the margin attributes appear and change accordingly.
You cannot have more ids in your html template. You can have only one id="scrl-li".
In you html template replace the id with class and in the jquery instead of calling $("#scrl-li"), you will have to use $(".scrl-li").
Hope this will help you.
I want to pass which li is clicked. The clicked li number i have to pass through onclick function. There is no id is defined to any li.
Example is second li is clicked, i want to pass onclick="imageDisplayClick(2) but i am not able to get the count.
<div id="slider_text">
<ul onclick="imageDisplayClick()">
<li><h1 style="color:orange;">SPORTS & FITNESS</h1></li>
<li><h1>ACCU - CHEK Strips</h1></li>
<li><h1>NATURE'S BOUNTY</h1></li>
<li><h1>Beauty Care</h1></li>
</ul>
</div>
Please help me to solve this issue
For starters, I would not recommend using the onclick attribute, but rather making use of Unobtrusive JavaScript and separating it out to a function.
After separating out the logic, it's only a small extra step to loop over the elements, which can be acquired with .querySelectorAll.
From here you now have a click handler on each individual <li> element that can reference the element in question with the this keyword. Because you have access to the element directly, you shouldn't actually need to pass through the relevant offset into the function in question.
var points = document.querySelectorAll('#slider_text > ul > li');
for (var i = 0; i < points.length; i++) {
points[i].addEventListener('click', function() {
console.log(this.innerHTML);
})
}
<div id="slider_text">
<ul>
<li>
<h1 style="color:orange;">SPORTS & FITNESS</h1>
</li>
<li>
<h1>ACCU - CHEK Strips</h1>
</li>
<li>
<h1>NATURE'S BOUNTY</h1>
</li>
<li>
<h1>Beauty Care</h1>
</li>
</ul>
</div>
Hope this helps! :)
Use this, it will pass a reference to the DOM element itself.
<ul onclick="imageDisplayClick(this)">
You should consider using https://developer.mozilla.org/fr/docs/Web/API/EventTarget/addEventListener as it makes everything lie in your javascript file and prevents from having js fragments scattered in your html.
You can then use the event parameter to find out in detail what was clicked:
Test it here https://jsfiddle.net/jteLw8qa/
HTML:
<div id="slider_text">
<ul id="selection">
<!-- data-XXX can be accessed in javascript with element.dataset.XXX AS A STRING -->
<li data-yourdata="42"><h1 style="color:orange;">SPORTS & FITNESS</h1></li>
<li data-yourdata="elephant"><h1>ACCU - CHEK Strips</h1></li>
<li data-yourdata="pink"><h1>NATURE'S BOUNTY</h1></li>
<li data-yourdata="stackoverflow"><h1>Beauty Care</h1></li>
</ul>
</div>
JS:
function imageDisplayClick(event)
{
// find the clicked li element
var target = event.target;
// find first parent li or ul
while(target.tagName != 'LI' && target.tagName != 'UL')
target = target.parentNode;// because you have <h1> in your <li>
// if li is a parent the user clicked on it, else he clicked on the side but still on the ul
if(target.tagName == 'LI')
alert('clicked li with data-yourdata=' + target.dataset.yourdata);
}
// have the click event being listened on our ul#selection element
document.getElementById('selection').addEventListener('click', imageDisplayClick);
On top of the other answers provided, an event argument is also passed to the click handler, which should provide you with information on what specific thing was clicked on.
In your case, you could do something like this:
imageDisplayClick = function(event){
var target = event.target.tagName=="H1"?event.target.parentNode:event.target;
console.log(target);
}
<div id="slider_text">
<ul onclick="imageDisplayClick(event)">
<li><h1 style="color:orange;">SPORTS & FITNESS</h1></li>
<li><h1>ACCU - CHEK Strips</h1></li>
<li><h1>NATURE'S BOUNTY</h1></li>
<li><h1>Beauty Care</h1></li>
</ul>
</div>
I am making a menu that has submenu. When I click on a menu item I am using prevent default because it is a tags, but on the submenu level I don't want to prevent default. I haven't been able to figure out how to make it work so it doesn't affect the top level.
<div id="block-menu-block-2">
<ul class="menu">
<li>
1
</li>
<li>
2
<ul class="menu">
<li>2.1</li>
<li>2.2</li>
<li>2.3</li>
<li>2.4</li>
</ul>
</li>
<li>
3
<ul class="menu">
<li>3.1</li>
<li>3.2</li>
<li>3.3</li>
<li>3.4</li>
</ul>
</li>
<li>
4
</li>
<li>
5
</li>
<li>
6
<ul class="menu">
<li>6.1</li>
</ul>
</li>
</ul>
</div>
Here is the jQuery
$('#block-menu-block-2 ul li').on("click", function() {
if ($(this).children().is('ul')) {
if ($(this).find('ul').is(':visible')) {
$(this).find('ul').hide("blind");
$(this).removeClass('menuItemSelected');
$(this).find('ul').removeClass('menuItemSelected');
} else {
$(this).parent().find('li ul').hide("blind");
$(this).parent().find('.menuItemSelected').removeClass('menuItemSelected');
$(this).find('ul').show("blind");
$(this).addClass('menuItemSelected');
$(this).find('ul').addClass('menuItemSelected');
};
event.preventDefault()
}
});
Here is a codepen for reference: http://codepen.io/mathiasha/pen/bVpMyo
Added some stuff. Changed some stuff. Couldn't paste into codepen from my phone so this might not work. Code first, then word wall.
$('#block-menu-block-2 ul li').each (function () {
var $this = $(this);
if ($this.find ('ul:first').length > 0) {
$this.click (function () {
if ($this.find ('ul:visible').length > 0) {
$this.removeClass ('menuItemSelected').find ('ul').removeClass('menuItemSelected').hide ('blind');
} else {
$this.parent ().find ('ul li').hide ('blind');
$this.parent ().find('.menuItemSelected').removeClass ('menuItemSelected');
$this.addClass ('menuItemSelected').find ('ul').show ('blind').addClass ('menuItemSelected');
}
});
}
});
$('#block-menu-block-2 > ul > li > a').click (function (e) {
if ($(this).find ('ul:first').length > 0)
e.preventDefault ();
});
The real answer lies in only putting the preventDefault only on the a tag and only when it is the immediate child of a li tag tjat is the immediate child of a ul tag that is the immediate child of the block-menu. See the last 3 lines.
The rest of the code below should only add the click listener to li tags with ul tags inside. Tried to use chaining to limit the number of jQuery objects created. Might have messed up what it was doing. You only really need to remove preventDefault from where it is and than use the last 3 lines.
Can you not add a class to your submenu triggers, e.g. .submenu-trigger, and then use the following jQuery:
$(document).on('click', function(e) {
if ($(e.target).hasClass('submenu-trigger')) e.preventDefault();
});
Ignoring all the other menu manipulation and putting the event on <a> tags you can simply check if the <a> has a sibling <ul> and if it does prevent default
$('#block-menu-block-2 a').click(function(e){
if( $(this).siblings('ul').length ){
e.preventDefault();
}
// menu manipulation code
});
I've got this html below.
I need all div's inside div#ProductImagesContainer to be hidden at startup, all but div#productImageA.
When you click a.productImageB, the corresponding div#productImageB inside div#ProductImagesContainer should be shown and it's siblings should hide.
I need to use Prototype for this project, but I'm not a javascript genious. Would know what to do with jQuery but can't do it with Prototype.
<ul>
<li>
A
</li>
<li>
B
</li>
<li>
C
</li>
<li>
D
</li>
</ul>
<div id="ProductImagesContainer">
<div id="productImageA">maybe flash video</div>
<div id="productImageB">imageB</div>
<div id="productImageC">imageC</div>
<div id="productImageD">imageD</div>
</div>
My JavaScript is a bit rusty, but I believe you want the following:
Hide everything:
$$('#ProductImagesContainer div').invoke('hide');
Show the one you want:
$('ProductImageA').show();
Edit: documentation on prototype's api can be found here
Here is the jsfiddle to achieve what you are looking for in prototype:
Given HTML:
<ul>
<li>
A
</li>
<li>
B
</li>
<li>
C
</li>
<li>
D
</li>
</ul>
<div id="ProductImagesContainer">
<div id="productImageA">maybe flash video</div>
<div id="productImageB">imageB</div>
<div id="productImageC">imageC</div>
<div id="productImageD">imageD</div>
</div>
Prototype JavaScript:
//declare global variables to access within functions and etc...
var myLi = $$('li'); //get all the li a links
var myDiv = $('ProductImagesContainer').children; //get all the children of div#ProductImagesContainer
hideAllBut(null); //first hide all the divs
//function to hideAllBut the child div element of #ProductImagesContainer w/ the following classname as id
function hideAllBut(el) {
var toShow = el;
for (var index = 0; index < myDiv.length; index++) {
if (myDiv[index].identify() == toShow)
myDiv[index].show();
else
myDiv[index].hide();
};
}
//oops through each li
myLi.each(function(myLiEl) {
//attached on click event for each of the hyperlinks and use the hyperlink's class name to call hideAllBut(theclassname)
Event.observe(myLiEl, 'click', function() {
hideAllBut(myLiEl.firstDescendant().className); //gets the className of first decendant based on your example
});
});
First we declare two global variables to hold all the li's a links and children of div#ProductImagesContainer. Then we create a function called hideAllBut(el); where it hides all but the child div element of #ProductImagesContainer w/ the classname as id. A parameter, which is the classname of link that is associated w/ the div element's id name that we need to hide. Then we proceed to oop through each li and add an onclick event so whenever the li is clicked it'll call hideAllBut(); and pass its classname as the param.
Based on kjy112's detailed answer, here is a shorter version.
HTML:
<ul id="ProductImagesLinks">
<li>
A
</li>
<li>
B
</li>
<li>
C
</li>
<li>
D
</li>
</ul>
<div id="ProductImagesContainer">
<div id="productImageA">maybe flash video</div>
<div id="productImageB">imageB</div>
<div id="productImageC">imageC</div>
<div id="productImageD">imageD</div>
</div>
Javascript:
$('ProductImagesLinks').on('click', 'a', function(event, element){
var target = $(element.readAttribute('data-target'));
if (target) {
target.show();
$$('#ProductImagesContainer > div[id!='+target.identify()+']').invoke('hide');
}
});
$('ProductImagesContainer').down().siblings().invoke('hide');
The advantage here is it adapts if the list changes by utilising event bubbling.