edit: For new viewers of the question, my title is misleading. The solution to this problem had nothing to do with event bubbling/capturing as was my assumption at the time of posting.
I have a mobile navigation menu that contains 3 <li> elements which, when clicked, toggleSlide() a dropdown menu. The jQuery code for each of them is largely the same:
const coreSlider = function() {
const aContainer = document.querySelector('#dropdown-A');
const aLinks = document.querySelector('#A-links');
const dontOpen = document.querySelector('.mob-prev-def');
$(aContainer).on('click', function() {
$(aLinks).slideToggle(200);
});
$(dontOpen).on('click', function(e) {
e.preventDefault();
});
}
...
Above is an example of the jQuery code on 1 of these dropdown containers, and behaves exactly as I want it to (toggles the drop-down menu on click, but does not redirect to the href value inside the <li> inside the container. However, I still want the links that appear on click to direct them to the relevant part of my website.
There are 2 more containers with jQuery code exactly like this, but for whatever reason the e.preventDefault() part of the code on them doesn't work as intended, and redirects on click. I figure that event bubbling/ capturing has something to do with it, but I'm not sure how exactly it is functioning in this example. To that end, what's going on here and how can I fix it to ensure all containers behave as I want? Here's my HTML:
<ul id="nav-links">
<li id="dropdown-A">
...
<div id="A-links">
...
...
...
</div>
</li>
<li id="dropdown-D">
...
<div id="D-links">
...
...
...
...
</div>
</li>
<li id="dropdown-E">
...
<div id="E-links">
...
...
</div>
</li>
<li id="gallery">Gallery</li>
</ul>
Edit: thanks to user Stone3m, I managed to add in a solution:
const prevDef = function() {
const dontOpen = $('.mob-pref-dev');
$(dontOpen).on('click', function(e) {
e.preventDefault();
});
}
prevDef();
The issue here is that you are using querySelector, which only selects one occurrence.
You should be using querySelectorAll with a forEach loop for every occurrence.
A quick and simple method would be to:
document.querySelectorAll('.mob-prev-def').forEach(item => {
item.addEventListener('click', function(e) {
e.preventDefault()
})
})
Sorry, I prefer vanilla JavaScript, but you could figure it out in jQuery now (I hope!)
Related
I've found multiple threads based on or around this question however the answers so far haven't helped what so ever. I'm trying to get this to work through pure JavaScript (JQuery accepted).
So far I have it working so that I can select an item via web browser on a computer but the click event doesn't seem to work with touch screens. I've tried multiple "solutions" from other threads such as adding touch for example:
$('.List').on('click touch', function () {
// code
});
My current JavaScript (Works on pc):
document.querySelector('.List').addEventListener('click', function (e) {
var selected;
if (e.target.tagName === 'LI') {
selected = document.querySelector('li.selected');
if (selected)
selected.classList = '';
e.target.classList = 'selected'
}
document.getElementById('ItemValue').value = e.target.innerText;
});
In the above JavaScript I'm simply adding a colour to the background of the list item and getting the inner text and storing it.
My list (Items are added at runtime)
<div id="SelectedItems" class="ListBox">
<ul id="Selected" class="List ItemList" runat="server" >
<%--List items here--%>
</ul>
</div>
If you sure, you are including the Jquery library, try using this solution.
Since all your list items are loading at run time, you can also use like this,
$(document).ready(function () {
$(document).on('click', '#Selected li' function () {
// code
});
});
I'm using a jQuery grid slider plugin that I'd like to run again after DOM manipulation.
I suspect my issue is similar to this - Any way to rerun a jQuery plugin after DOM modification? - but my attempts aren't work.
Here's the setup:
When the page loads, the grid plugin js and the options js run against an unordered list, like such:
<div class="panel">
<div class="g-container">
<div class="g-slider">
<div class="tiles">
<ul>
<li><img src="Images/image-01.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/image-03.jpg"><div><h1>electronics</h1></div></li>
<li><img src="Images/image-02.jpg"><div><h1>medical</h1></div></li>
<li><img src="Images/image-11.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/image-02.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/image-09.jpg"><div><h1>medical</h1></div></li>
<li><img src="Images/image-11.jpg"><div><h1>electronics</h1></div></li>
</ul>
</div>
</div>
</div>
</div>
...and create the grid slider. Here's an example of what it looks like: http://1.s3.envato.com/files/27300390/index.html
This all works fine.
(Long story short) I have a large list of categories that are all grouped together that I've placed in a div holder, like so:
<div id="listing-holder">
<ul>
<li><img src="Images/car-01.jpg"><div><h1>automotive</h1></div></li>
<li><img src="Images/car-01.jpg"><div><h1>electronics</h1></div></li>
...
</ul>
</div>
These categories are dynamically created and in one large (hidden off the page) group. So there may be, say, 20 categories, and 100 items (in my example, the images). The items may appear in more than one category, though I only want to show one at a time.
Elsewhere on the page are some navigation links. When one of these links is clicked, the items in #listing-holder are copied into .tiles ul. Then it's name is checked against the header tags in .tiles ul, removing any items that do not match. Then, I want the plugin to run again so that the pagination and slider work as before the change, but with new paging (if it's more or less). Like so:
$("#left-menu").delegate("a", "click", function(e) {
var itemClicked;
itemClicked = $(this).text();
$('.g-container .g-slider .tiles').html('');
$('.g-container .g-slider .tiles').html($('#listing-holder').html());
$(".g-container .g-slider .tiles h1:not(:contains(" + itemClicked + "))").closest('li').remove();
init(); // this isn't working the way I expected it to
});
Here's the (pertinent information from the) options js:
$(document).ready(
function() {
var $panel = $(".panel");
var $container = $panel.find(".g-container");
... // more variables
$(".g-container").gridSlider({
num_cols:5,
num_rows:3,
... // more settings
});
$submitButton.click(function() {
$container.undoChanges()
.setGridSize($gridCol.val(),$gridRow.val())
.setNoCategory($categories.filter(":checked").val() == "no")
... // more settings
.updateChanges(); // this is in the grid.js
setPanelWidth();
});
$resetButton.click(function() {
init();
$submitButton.trigger("click");
});
var init = function() {
$gridCol.val(5);
$gridRow.val(3);
... // more settings
}
var setPanelWidth = function() {
var width = $container.find(">div").outerWidth();
if (width < panelWidth) {
width = panelWidth;
}
$panel.css({width:width, marginLeft:-width/2});
... // more settings
}
init();
}
);
I've tried calling the init function, which does call it, but nothing seems to happen. I placed alerts at the beginning and end of the grid.js (which is minified), and they both fired, so it seems like it's going through.
I thought I'd have to use something like this:
(function( $ ){
$.fn.myPlugin = (function(){
{
// do something...
}
});
})(jQuery);
...but since I was able to call init from the options.js, I didn't go that route (but I'm willing to re-visit this, as I may have implented it incorrectly).
I've been at this for about a week, and I suspect I'm approaching this wrong, and could use some direction.
I think I could resolve the issue by creating all of the categories, then using something like getScript() to run afterwards. I think that would work. The issue is that there may potentially be several dozen categories, with items that may appear in several.
I figured (working with the hand dealt) that if I have just one list and pick from that list what I need depending on a click, that would be the route to go. I can do that successfully. It's just hooking it up to the slider that's not working.
Let me know if I need to provide further details.
Thanks.
Stephen
I am not familiar with the grid-slider plugin. But have you tried completely destroying the container DOM and then re-creating and inserting it. Then call the .gridSlider function again on the newly created DOM?
I have been trying every combination under the sun of parent()/children()/find() and selector syntax to .show() an element of my webpage that i hid on document ready, but I just can't get it to work! I'd really appreciate it if someone could take a look..
If you go to the portfolio section you can see it live here -> http://holly.im/ .
In any case the html looks something like this:
<div id="portfolio">
<h1>Heading</h1>
<div class ="little_column">
<div class="project">
click
</div>
</div>
<div id="c++_games_engine_construction" class="big_column">
<?php include "projects/C++_game_engine_construction.php"; ?>
</div>
</div>
And the relevant jquery:
$(document).ready(function() {
//hide all the big_columns /
// project details within the portfolio page
$('#portfolio').find('.big_column').hide(); //This seems to be working
});
$(function(){
$('.project').click(function () {
var selectedProject =
$(this).children('a.projlink').attr('href');
$(this).parent().parent().find(selectedProject).show(); //My most recent attempt, I though maybe i needed to go up the heirachy then back down? But whatever i try it doesn't show.
return false;
});
});
That's it really, thanks!
Having the character + in the ID of an element causes jQuery to become confused because the + character is reserved for the Next Adjacent Selector.
If you remove those characters from your code, it works just fine. As was mentioned in one of the comments to this answer, since the href is essentially the ID of the item to be shown, you can select it directly.
HTML
<div id="portfolio" class="section">
<h1>Heading</h1>
<div class="little_column">
<div class="project"> click
</div>
</div>
<div id="c_games_engine_construction" class="big_column">
I'm hidden at first!
</div>
</div>
JS
$(document).ready(function () {
//hide all the big_columns /
// project details within the portfolio page
$('#portfolio').find('.big_column').hide(); //This seems to be working
});
$(function () {
$('.project').click(function () {
var selectedProject = $(this).children('a.projlink').attr('href');
$(selectedProject).show(); //My most recent attempt, I though maybe i needed to go up the heirachy then back down? But whatever i try it doesn't show.
return false;
});
});
jsfiddle
The issue is with the + in the selector. It needs to be escaped because it has special meaning in the Selectors API (and is invalid for an ID).
If you removed the ++ from the href and the id, it works.
Alternately, you can do .replace(/\+/g, "\\+")
var selectedProject = $(this).children('a.projlink').attr('href').replace(/\+/g, "\\+")
Off topic: You don't need two .ready() calls, which is what you have, but using different syntax.
As others have mentioned, your problem are the + characters mistreated by jQuery. So the simple solution is: do not use jQuery - or at least, not for the selector thing. Since every target you have is an id selector, we can easily change it to
$(document).ready(function() {
$('#portfolio').find('.big_column').hide();
$('.project').click(function () {
var selectedProject = $(this).find('a').attr('href'); // a littebit simplified
var el = document.getElementById(selectedProject.slice(1));
$(el).show();
return false;
});
});
What i want to do is swapping two HTML DOM nodes.
Let's take the following HTML list and the swap button below:
<ul class="center-text">
<li>0</li>
<li>1</li>
<li>2</li>
</ul>
<form class="center-text">
<button id="swapButton">Swap</button>
</form>
And here is my JS code:
// the "ready" method is the only jQuery method used in the code
$(document).ready(function(){
document.getElementById("swapButton").onclick = function() {
var ul = document.getElementsByTagName("ul")[0];
// pseudo-swapping: insert "child2" before "child0"
// (indexes are 1 and 5 because of the TextNodes between list nodes)
ul.insertBefore(ul.childNodes.item(5), ul.childNodes.item(1));
}
});
So here is what happens when clicking the swap button:
The items are swaped indeed. But Somehow after (let's say 1/4) seconds they are restored to their original position, i.e. swaped back automatically.
My question is: WHY?
PS: the code is merely for educational purposes and i only try to understand what's going on behind the doors, so please do NOT post any alternative jQuery method.
$(document).ready(function(){
document.getElementById("swapButton").onclick = function(e) {
e.preventDefault();
var ul = document.getElementsByTagName("ul")[0];
ul.insertBefore(ul.childNodes.item(5), ul.childNodes.item(1));
}
});
This is because button redirects the page to same page. And reverts all. You need to prevent the default behaviour of button.
I am trying to maintain state in my JQuery accordion menu, I'd like to avoid any server-side processing or unnecessary variable passing if possible.
Here is my code:
<ul class="accordion">
<li>
Autos
<div class="slide">
<ul>
<li>Cars</li>
<li>Motorbikes</li>
</ul>
</div>
</li>
<li>
Pets
<div class="slide">
<ul>
<li>Cats</li>
<li>Dogs</li>
</ul>
</div>
</li>
</ul>
<script type="text/javascript">
$(document).ready(function() {
var accordion = $('ul.accordion');
var show_link = '/cats';
active = FIND_SECTION_TO_OPEN_BASED_ON_URL;
accordion.accordion('activate', active );
});
</script>
By hardcoding
accordion.accordion('activate', 0 );
I can have the "Autos" menu open when the page loads, but I want to be about to dynamically find which menu or ul to open based on the URL, I'm pretty new to JavaScript and where I am stuck is on this line:
active = FIND_SECTION_TO_OPEN_BASED_ON_URL.to_int;
Does anyone know how to implement this?
(I've done a lot of research on this and have not been able to find a solution which works here)
You can use the location.hash property to get the menu to open from the URL. You would pass the menu number in a hash tag like this:
URL: http://www.domainname.com/page.html#1
And then use the JS to get it and pass it to the script:
<script type="text/javascript">
$(document).ready(function() {
var accordion = $('ul.accordion');
var show_link = '/cats';
var active = window.locatioh.hash.replace("#", "");
accordion.accordion('activate', active );
});
</script>
First off you need to pass the current page via the anchor like so (What you pass doesn't really matter, just that it's unique):
Autos
...
Pets
Then you can base the index off of the resultant hash
active = $(".opener[href='"+location.hash+"']").parents("li").index();
Here's what I did for my page. My URLS are in the format site.com/#page/accordion/tab. I also made it so that when the user clicks on an accordion or tab, the hash changes. That way if you were to navigate to the URL somewhere else, you would go to the accordion you were just looking at.
I did run into a problem though with the hashchange event. Since it's a hash, if the user goes from site.com/#page/accordion-one to site.com/#page/accordion-two, that's a hashchange not a pageload, so I put the below code in a function and bound it to the hashchange event. Problem is I have to unbind it when I change the hash in the below code, and I'm having some trouble with it still catching the hashchange event when I rebind it.
See my question here.
var hash = window.location.hash;
hash = hash.replace(/#/, "");
hash = hash.split("/");
if(typeof hash[1] !== 'undefined'){
//select campus accordion
//first disable the animation and the function that changes the hash:
$("#accordion").accordion("option", "animated", false);
$('.ui-accordion').unbind('accordionchangestart');
$("#accordion").accordion("activate", $("#accordion-"+hash[1]));
$("#accordion").accordion("option", "animated", 'slide');
$('.ui-accordion').bind('accordionchangestart', function(event, ui) {
var hash = window.location.hash;
hash = hash.replace(/#/, "");
hash = hash.split("/");
var name = $(ui.newHeader).attr("name");
var val = hash[0]+"/"+name;
sessionStorage.setItem("accordion", val);
hashChange(val);
});
}
if(typeof hash[2] !== 'undefined'){
//select tab
$(".ui-tabs").tabs("select", "#tabs-"+hash[2] );
}
My new library does this. Check it out.