If there were two <ul>'s, one called list_a and the other called list_b, using javascript and not using any libraries like jQuery, how would you delete the <li>'s in list_a that have the same value as those in list_b?
Heres the example HTML:
<ul id="list_a">
<li value="1">list_a_0</li>
<li value="8">list_a_8</li>
<li value="9">list_a_9</li>
</ul>
<ul id="list_b">
<li value="8">list_b_8</li>
<li value="9">list_b_9</li>
<li value="2">list_b_2</li>
</ul>
The end result should be:
<ul id="list_a">
<li value="1">list_a_0</li>
<!-- DELETED TWO <li>'s -->
</ul>
<ul id="list_b">
<li value="8">list_b_8</li>
<li value="9">list_b_9</li>
<li value="2">list_b_2</li>
</ul>
The javascript so far that I can build (that doesn't work) is:
window.onload=function()
{
init();
function init()
{
var listA = document.getElementById("list_a");
for(var i in listA.childNodes)
{
var x = listA.childNodes[i];
var listB = document.getElementById("list_b");
for(var j in listB.childNodes)
{
var y = listB.childNodes[j];
if(x.innerHTML == y.innerHTML)
listA.removeChild(listA);
}
}
}
}
Thanks!
DEMO: http://jsfiddle.net/rmXrZ/
window.onload = function() {
var listA = document.getElementById("list_a");
var listB = document.getElementById("list_b");
for (var i = 0; i < listA.children.length; i++) {
var x = listA.children[i];
for (var j = 0; j < listB.children.length; j++) {
var y = listB.children[j];
if (x.value == y.value) {
listA.removeChild(x);
i--;
}
}
}
}
Don't use for-in for iteration of numeric indices
Cache the DOM selection instead of re-selecting in the loop
Use .children instead of .childNodes to avoid text nodes between elements
Compare .value instead of .innerHTML
Remove x instead of listA
When an element is removed from listA, decrement i, because removal from the DOM means removal from the .children collection.
function init() {
var listA = document.getElementById("list_a");
var listB = document.getElementById("list_b");
for(var i =0; i<listA.children.length;i++) {
var x = listA.children[i];
for(var j in listB.children) {
var y = listB.children[j];
if(x.value == y.value)
x.parentNode.removeChild(x);
}
}
}
Avoid hitting the DOM on multiple occasions, also in this case children is a better choice of data.
Related
I need to get the this.element index on a eventListener click. I looked for a good index solution but i didn't understand most of them.
<div class="navbar">
<ul>
<li class="menu">Link 1</li>
<li class="menu">Link 2</li>
<li class="menu">Link 3</li>
<li class="menu">Link 4</li>
<li class="menu">Link 5</li>
</ul>
</div>
Now i need my loop var to match my index like this
var $menuItem = document.getElementsByClassName('menu');
for ( var x = 0; x < $menuItem.length; x++ ){
$menuItem[x].addEventListener('click', function(){
if (this.toString() + index == $menuItem[x]){
$menuItem[x].classList.add('active')
}
})
}
I know this may not be the best way to add a link to a this element but i need the index for another function.
You already have the index. The x variable. You can use a self-invoking function for remembering it in the corresponding handler:
for (var x = 0; x < $menuItem.length; x++) {
(function(index) {
$menuItem[index].addEventListener('click', function() {
// ...
})
})(x)
}
Another option is using Array#indexOf function:
// Convert the `HTMLCollection` into a regular array!
var $menuItem = [].slice.call(document.getElementsByClassName('menu'));
for (var x = 0; x < $menuItem.length; x++) {
$menuItem[x].addEventListener('click', function() {
var index = $menuItem.indexOf(this);
})
}
Another option is using Array#forEach method:
[].forEach.call(document.getElementsByClassName('menu'), function(el, index) {
el.addEventListener('click', function() {
// `index` refers to clicked element index in the collection
})
});
I have a unordered list and the li elements can be dragged and the order can be changed. This works fine the problem happens I use this line of code:
var items = ul.getElementsByTagName("li");
It will return HtmlCollection but in the original order and not the current order that the user has moved the list items into.
I captured a screenshot with Chrome on the order that the list is in after I have moved several of the li's around. Notice how it is still ordered like it was shown initially?
But if I expand the [0 ... 99] tag I see the proper order. (See how the top few have been moved? This is the order I need to iterate through.)
And here is the html text.
<ul id="first_" class="sortable_unstyled" data-sortable-id="0" aria-dropeffect="move">
<li draggable="true" role="option" aria-grabbed="false" style="list-style-type: none;" id="first_li_0" >
<div>
<input id="first_sectionnumber_0" type="number" />
</div>
</li>
<li draggable="true" role="option" aria-grabbed="false" style="list-style-type: none;" id="first_li_1" >
<div>
<input id="first_sectionnumber_1" type="number" />
</div>
</li>
// There is more than a 100 more lis after these
</ul>
The javascript function is:
function RenumberQuestionIndexes(ulObj) {
var count = 0;
var ul = document.getElementById(ulObj);
var items = ul.getElementsByTagName("li");
var indexinput = ulObj + "order_index_";
for (var i = 0; i < items.length; ++i)
{
if(items[i].style.display.indexOf('none') >= 0)
{
document.getElementById(indexinput + i.toString()).value = -1;
}
else
{
document.getElementById(indexinput + i.toString()).value = count;
count++;
}
}
}
So how can I iterate through that HtmlCollection items list and get the actual order that is currently displayed on the screen?
Well after alot of head banging. I found that if I turned my var items into a array it will work.
So I changed the code to this:
function RenumberQuestionIndexes(ulObj) {
var count = 0;
var ul = document.getElementById(ulObj);
var items = ul.getElementsByTagName("li");
var indexinput = ulObj + "order_index_";
var a = Array.from(items);
for (var i = 0; i < a.length; ++i)
{
if(a[i].style.display.indexOf('none') >= 0)
{
document.getElementById(indexinput + i.toString()).value = -1;
}
else
{
document.getElementById(indexinput + i.toString()).value = count;
count++;
}
}
}
The new array has the correct current order of the list items.
I would love to know how Array.from() does that magic.
For some reason I need to loop through various elements and change their style when they are clicked. This is the code(https://jsfiddle.net/wd4z1kvs/1/) I am trying:
var myscroll = {};
myscroll.list = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li");
for( var j=0; j < 5; j++) {
myscroll.list[j].anchor = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li")[j].getElementsByTagName("a")[0];
myscroll.list[j].anchor.addEventListener("click", function() {
alert(j);
myscroll.list[1].anchor.innerHTML = "hello" + j;
myscroll.list[j].anchor.innerHTML = "yellow" + j;
});
}
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>Artists</li>
<li>Songs</li>
<li>Beats</li>
<li>Contact</li>
</ul>
</div>
The problem seems to be that the event works with j's present value. It doesn't take the value of the parameter when the code was actually run.
The simplest solution is to use a forEach, or some other looping callback function:
myscroll.list.forEach(function(item, j) {
item.anchor = document.getElementsByClassName("navbar-right")[0]
.getElementsByTagName("li")[j]
.getElementsByTagName("a")[0];
item.anchor.addEventListener("click", function() {
alert(j);
myscroll.list[1].anchor.innerHTML = "hello" + j;
item.anchor.innerHTML = "yellow" + j;
});
});
Try this:
var myscroll = {};
myscroll.list = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li");
for( var j=0; j < 5; j++) {
(function(j) {
/* j variable is just a local copy of the j variable from your loop */
myscroll.list[j].anchor = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li")[j].getElementsByTagName("a")[0];
myscroll.list[j].anchor.addEventListener("click", function() {
alert(j);
myscroll.list[1].anchor.innerHTML = "hello" + j;
myscroll.list[j].anchor.innerHTML = "yellow" + j;
});
}(j));
}
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>Artists</li>
<li>Songs</li>
<li>Beats</li>
<li>Contact</li>
</ul>
</div>
As noticed #Andreas there is a closure in a loop.
The events don't remember values, they only keep a link (reference) to
the environment where they were created. In this case, the variable j
happens to live in the environment where the three events were
defined. So, all events, when they need to access the value, reach
back to the environment and find the most current value of j. After
the loop, the j variable's value is 5. So, all five events point to
the same value.
use this:
var myscroll = {};
var list = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li");
myscroll.list = list;
for (var j = 0; j < 5; j++) {
var anchor = list[j].getElementsByTagName("a")[0];
anchor.setAttribute("index",j);
myscroll.list[j].anchor = anchor;
anchor.addEventListener("click", function () {
alert(this.getAttribute("index"));
this.innerHTML = "hello" + this.getAttribute("index");
//this.innerHTML = "yellow" + this.getAttribute("index");
this.style.backgroundColor = "yellow";
});
}
Hi I was wondering if anyone could help me out. I need to apply an array I created in Java Script on the HTML page that already has the order list created.I keep on getting error messages that say "Cannot read property of 'inner.HTML' undefined.
Any help would be greatly appreciated:)
thanks!
Here is my code:
< div id = "results" >
< ul >
< li id = "1-1" > < /li>
<li id="1-2"></li >
< li id = "1-3" > < /li>
<li id="1-4"></li >
< li id = "1-5" > < /li>
</ul >
< /div>
</article >
< script >
//declared global variable with an array of variables.
var places = ["Switzerland", "Canada", "Australia", "Norway", "New Zealand"]
// function to place the country's name in the
// li id.
function processPlaces() {
var locations = "";
for (var i = 0; i < places.length; i++) {
var listItem = i + 1;
var list = document.getElementById("1-" + listItem);
locations = list.getElementsByTagName("li");
locations[1].innerHTML += places[i];
}
}
//runs setUpPage () function when page loads.
if (window.addEventListener) {
window.addEventListener("load", processPlaces, false);
} else if (window.attachEvent) {
window.attachEvent("onload", processPlaces, false);
} < /script>
ids cannot start with a number, so preface them with l or some letter (you can see the change in the snippet).
HTML elements cannot have spaces immediately following <, so < div> will render as text, and < /div> will also render as text. Make sure to remove all the excessive spacing.
Further, when you access the element with getElementById that is the actual <li> element, and using getElementsByTagName inside of that element will find nothing because there are no children to the <li> elements. Instead of taking that approach, remove it and simply use the <li> element you already have from using getElementById. Once you make these changes, your code should run as intended.
//declared global variable with an array of variables.
var places = ["Switzerland", "Canada", "Australia", "Norway", "New Zealand"]
// function to place the country's name in the
// li id.
function processPlaces() {
var locations = "";
for (var i = 0; i < places.length; i++) {
var listItem = i + 1;
var list = document.getElementById("l1-" + listItem);
list.innerHTML = places[i];//directly access <li> element
//locations = list.getElementsByTagName("li");
//locations[1].innerHTML += places[i];
}
}
//runs setUpPage () function when page loads.
if (window.addEventListener) {
window.addEventListener("load", processPlaces, false);
} else if (window.attachEvent) {
window.attachEvent("onload", processPlaces, false);
}
<div id = "results">
<ul>
<li id = "l1-1"></li>
<li id = "l1-2"></li >
<li id = "l1-3"></li>
<li id = "l1-4"></li >
<li id = "l1-5"></li>
</ul >
</div>
If the array is ordered already, why not just append to the <ul>? First set and id on your unordered list <ul id="myList">
for (var i = places.length - 1; i >= 0; i--) {
$('#myList').after($('<li />', { 'text': places[i] }));
};
JSFiddle
Cleaned it up a bit.
You can't have spaces right after < in your html tags.
Also, you cant start IDs with numbers.
Edit: Too slow, Travis answer explains this much better :)
var places = ["Switzerland", "Canada", "Australia", "Norway", "New Zealand"];
function processPlaces() {
for (var i = 0; i < places.length; i++) {
document.getElementById('a-' + (i+1)).innerHTML = places[i];
}
}
if (window.addEventListener) {
window.addEventListener("load", processPlaces, false);
} else if (window.attachEvent) {
window.attachEvent("onload", processPlaces, false);
}
<div id="results">
<ul>
<li id="a-1"></li>
<li id="a-2"></li>
<li id="a-3"></li>
<li id="a-4"></li>
<li id="a-5"></li>
</ul>
</div>
I'm trying to check which li have been clicked in the unordered list. only the first li seems to work becouse it will alert 0 but rest of the li wont respond with an alert. Nodelist should contain element 0,1,2. Raw javascript only.
HTML
<ul class="slideshow-buttons">
<li></li>
<li></li>
<li></li>
</ul>
Javasript
var $ = function (selector) {
return document.querySelector(selector);
};
var knappar = $('.slideshow-buttons').getElementsByTagName('li');
for (var i = 0; i < knappar.length; i++) {
var knapp = knappar[i];
knapp.onclick = knappTryck;
}
Problem seems to be inside knappTryck
function knappTryck(){
var childs = $('.slideshow-buttons').getElementsByTagName("li");
for (var c = 0; c < childs.length; i++) {
if (this == childs[c])
alert (c);
break;
}
}
the problem is here:
for (var c = 0; c < childs.length; i++) {
you use element c to parse the vector but you increment i. Replace c with i or the other way around
Also add braces to the if statement
Since you are using jQuery, make it 100% with jQuery :)
This will work :)
jQuery Code:
$(document).ready(function() {
$(".slideshow-buttons li").live("click", function() {
alert($(this).index());
});
});
You can use a closure.
for (var i = 0; i < knappar.length; i++) {
var knapp = knappar[i];
knapp.onclick = (function(i){
return function(){
console.log(i, this); // this is the li you clicked, and i is the index
}
})(i);
}