javascript: swap DOM nodes - javascript

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.

Related

How does event bubbling/ capturing affect e.preventDefault()?

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!)

Issues while Displaying/Reading data through jquery

I'm trying to do is - Before application is ready, it reads some data from one of the external file, make a new dyanamic "li" based on the file content and then it renders that li on html.
Just to add some explanation - There are two "li" in code
1) Dynamic li - that generates after reading a line from file
2) Static li - that display static li
So, whenever i try to click on "Static link" it calls click event and display me result which works fine.However, when i click on dynamic link, it doesn't trigger the click event
Another thing i noticed, When application is ready it display "its now generating static link first" alert first then it displays "its now generating dynamic link". Potentially, it should display the "dynamically link" alert first and the static link alert afterwards.
HTML
<body>
<div class="ui-page ui-page-active" id="main">
<header>Open Fulfillment Order</header>
<div id="ordersList" style="text-align: left">
<ul id="dynamicList" style="text-align: left;padding-left: 70px;padding-top: 30px">
</ul>
</div>
</div>
</body>
File.txt
Order1, 3/15/2017, 2
Order2, 3/10/2017, 3
Order3, 3/30/2017, 4
order4, 3/20/2017, 2
Javascript file
$(document).ready(function() {
$.get('file/data.txt', function(data) {
alert("its now generating dynamic link");
var lines = data.split("\n");
for (var prop in lines) {
var orderData = lines[prop];
var splittedData = orderData.split(",");
// Dynamic link hard coded string will be repalced with actual order name
$("#ordersList ul").append('<li><span class="tab">Dynamic Link</span></li>');
}
});
alert("its now generating static link first");
$("#ordersList ul").append('<li><span class="tab">Static Link</span></li>');
});
$(document).ready(function() { //dom is now loaded in.
$('#dynamicList li').click(function() {
alert($(this).find('a').attr('data-value')); // this will alert data-value value.
});
});
Any idea why click event is not being called on Dynamic Link?
the issue could be that when you use
$('#dynamicList li').click(function() {
alert($(this).find('a').attr('data-value')); // this will alert data-value value.
});
jQuery only creates bindings for the li elements that currently exist on the page. If lis are added later, try using this instead
$(document).on('click', '#dynamicList li', function() {
alert($(this).find('a').attr('data-value')); // this will alert data-value value.
});

Initializing a jquery mobile widget on a page gives "Cannot read property 'jQuery....' of undefined"

Fiddle Example
The site has 2 (or more) pages defined in HTML like this:
<div id="page1" data-role="page">
<div data-role="content" id="page1-content">
Next Page
</div>
</div>
<div id="page2" data-role="page">
<div data-role="content" id="page2-content">
Go Back
</div>
</div>
In Javascript - I am at once initializing everything:
$(function(){
$('#page1-content, #page2-content').each(function(){
var ul = $('<ul>');
$.each(['one','two','three'], function(item){
ul.append('<li>'+item+'</li>');
});
ul.appendTo(this).listview();
});
});
But the page only initializes the list view on the 1st page, and the list view on the 2nd (and not currently visible) page does not initialize and gives me an error.
Cannot read property 'jQuery19107783124386332929' of undefined
What am I doing wrong?
I really want to be able to start fetching the data and at least create the DOM in every page at once in the beginning, rather than waiting till the user clicks "Next Page".
Also - the list view on the first page is overlapping the "Next" button. I see this overlapping often and would like to fix/understand this too.
Page data-role=page in jQuery Mobile passes through different stages, as shown in the diagram below.
Image / diagram source: http://bradbroulik.blogspot.co.nz/2011/12/jquery-mobile-events-diagram.html
Enhancing widgets manually should be called on active page only, otherwise it will result in a error.
To do add fresh elements on different pages, you need to do this when pagecreate or pagebeforecreate events occur, without the need to call any enhancement method. As the widget will be auto-initialized/enhanced during that stage.
Also, you have a mistake in your code where you didn't close ul tag. However, this didn't cause the error.
The below code shows how to add elements to different pages without the need to call any enhancement method manually.
$(document).on("pagecreate", "[data-role=page]", function (e) {
var ul = $('<ul data-role="listview" data-inset="true"></ul>'),
html = '';
$.each(['one', 'two', 'three'], function (item) {
html += '<li>' + item + '</li>';
});
ul.append(html);
$('[data-role=content]', this).append(ul);
});
Demo
This might be a particular issue of the versions combination you're using, but before checking that, I would try delegating on the 'pageinit' event instead of the regular document ready.
Please try this:
$(document).on('pageinit',function(){
$('#page1-content, #page2-content').each(function(){
var ul = $('<ul>');
$.each(['one','two','three'], function(item){
ul.append('<li>'+item+'</li>');
});
ul.appendTo(this).listview();
});
});

jQuery - how to determine which link was clicked

I have a simple piece of PHP which generates n copies of the following code:
<p class="ShowSDB_L2" class="center" onClick="FSD_L2('<?php print dbG;?>','<?php print $sLID;?>')">Click Here to See Data</p>
<div class="divSDB_L2">
</div>
It is generated using PHP, so the number of copies is unknown up front.
On another page I have the following Javascript (using jQuery)
function FSD_L2(dbG,SlID)
{
$(".divSDB_L2").load("test15.php?dbG="+dbG+"&SlID="+SlID).css('display','block');
}
When the text above (Click Here to See Data) is clicked, it should add the contents of test15.php between the the two DIV tags.
#Test15.php
<?php
$dbG = $_GET['dbG'];
$SlID = $_GET['SlID'];
print $dbG . " & " . $SlID;
?>
The problem I have is how to determine which of the links was clicked? At present, if I have three copies, and click one, all three copies are activated.
I hope I have made this clear enough. I'm sure there must be a simple way, but I'm quite new to Javascript/jQuery.
Like Brian said, you could just put the same class on all of your links and use the $(this) keyword in jQuery inside of a click function to find out which link was clicked.
Here's a basic example of changing link colors on a nav using this technique: http://jsfiddle.net/9E7WW/
HTML:
<a class="nav">Test</a>
<a class="nav">Test2</a>
<a class="nav">Test3</a>
<a class="nav">Test4</a>
Javascript:
$(document).ready(function(){
$('.nav').click(function(){
// change all to black, then change the one I clicked to red
$('.nav').css('color', 'black');
$(this).css('color', 'red');
});
});
Am not sure I fully understand what it is you are having difficulty with, but the following is how I would do it.
<p class="ShowSDB_L2" class="center" data-dbg="<?php print dbG;?>" data-slid="<?php print $sLID;?>">Click Here to See Data</p>
<div class="divSDB_L2"></div>
$(document).ready(function() {
$(document).on('click', 'p.ShowSDB_L2', function(evt) {
var $p = $(evt.currentTarget),
dbG = $p.data('dbg'),
slid = $p.data('slid'),
$div = $p.next();
FSD_L2(dbG, slid, $div);
});
});
function FSD_L2(dbG, SlID, $div)
{
$div.load("test15.php?dbG="+dbG+"&SlID="+SlID).css('display','block');
}
The click handler is not hardcoded to each p tag. Instead with each p tag we store the required data, ie dbg & slid.
The click handler is then attached once at document ready. jQuery abstracts over the various browsers and passes to its handlers the event object as its first parameter. This object can then be used to find the element on which the event occurred. Refer: http://api.jquery.com/on/
Finally, we fetch the required data from the clicked element, find the div that needs to be updated and then call your custom function.
Here is a cross-browser way to find the element (target) that triggered the event (e):
function getTarget(e){
// non-ie or ie?
e=e||window.event;
return (e.target||e.srcElement);
};
Add the complete URL to your link (or p in this case) using a data attribute:
<p class="ShowSDB_L2" class="center" data-loadurl="test15.php?dbG=<?php echo $dbG; ?>&SlID=<?php echo $SlID; ?>">Click Here to See Data</p>
<div class="divSDB_L2"></div>
Then do all the binding directly in your jQuery so you have direct access to the link that was clicked:
$(document).ready(function() {
$('.ShowSDB_L2').on('click', function(e) {
e.preventDefault();
$('.divSDB_L2').empty().load($(this).data('loadurl')).show();
});
});

Why $('a.current').removeClass('current'); is not working?

Why $('a.current').removeClass('current'); is not working for this jquery tabs?
http://jsfiddle.net/laukstein/ytnw9/8/
//full JS in http://jsfiddle.net/laukstein/ytnw9/8/
$(function(){
var list=$('#list'),
elementsPerRow=-1,
loop=true,
// find first image y-offset to find the number of images per row
topOffset=list.find('a:eq(0)').offset().top,
numTabs=list.find('li').length-1,
current,newCurrent;
function changeTab(diff){
// a.current set by jQuery Tools tab plugin
$('li.current').removeClass('current');
current=list.find('a.current').parent('li').addClass('current').index();
newCurrent=(loop)?(current+diff+numTabs+1)%(numTabs+1):current+diff;
if(loop){
if(newCurrent>numTabs){newCurrent=0;}
if(newCurrent<0){newCurrent=numTabs;}
}else{
if(newCurrent>numTabs){newCurrent=numTabs;}
if(newCurrent<0){newCurrent=0;}
}
// don't trigger change if tab hasn't changed (for non-looping mode)
if (current!=newCurrent){
list.find('li').eq(current).removeClass('current');
list.find('li').eq(newCurrent).addClass('current').find('a').trigger('click'); // trigger click on tab
}
}
list
// set up tabs
.tabs("#content",{effect:'ajax',history:true, xonBeforeClick:function(){changeTab(0)}})
// find number of images on first row
.find('a').each(function(i){
if(elementsPerRow<0&&$(this).offset().top>topOffset){
elementsPerRow=i;
}
});
//$('a').filter('.current').parent('li').addClass('current'); // Why does not work?
//$('a.current').parent('li').addClass('current'); // Why does not work?
$('ul#list li').click(function(){$('li.current').removeClass('current');$(this).addClass('current')});
$('a.current').removeClass('current'); // Why does not work?
});
HTML:
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<div id="content"></div>​
As far as I can tell (I don't yet have a working page running your code), but it appears that the "current" class is only applied to "li" elements.
I think your $("a.current") will always contain 0 elements.
it doesn't work because you haven't any <a> in your page with the class .current
You can check it out by yourself :
alert($('a.current').length);
will return you 0...
Your .removeClass() call is working does clear the class, but then this line in your history plugin:
links.eq(0).trigger("history", [h]);
Is triggering your it to load the first link as in the <iframe> as the default...which is selecting that link again, adding the class back, it's ultimately the tab plugin selecting the first tab and at this line:
tab.addClass(conf.current);
Adding the class back to the anchor (the anchor is tab at that point).
Here's your fiddle updated with an alert to see what's happening a bit easier.

Categories