JS Array output Trouble - javascript

I have an array of "active classes" as each class becomes active it gets added to my array. I would like to take that array test to make sure each class is only in it ONCE and then append its text to the dom as a li.
var filtersArray = [],
activeFilters = state.activeFilter.replace('.', ' ');
//by default .mix and none is in activeFilters
//.hatch,.sedan,.suv get added later -> these are the only ones I want
// activeFilters really equals -> activeFilters = ['.mix','.hatch','.sedan','.suv'];
if (activeFilters != ".mix" || activeFilters != "none") {
if ($.inArray(activeFilters, filtersArray) == -1) {
filtersArray.push(activeFilters);
for (index = 0; index < filtersArray.length; ++index) {
//console.log(filtersArray[index]);
$('.filter-result-list').append('<li>' + filtersArray + '<i class="close">x</i></li>');
}
}
}
jsFiddle: http://jsfiddle.net/im_cr/8zyhhftL/11/

Related

How to remove child (html div) from parentnode with for loop

So im trying to remove HTML div's from it's parent div.
I have a div which contains the div that need to be removed, selectedDivs.
However my current function refuses to remove more then 1 item from it's parent div...
Here's what i tried:
Console output: http://pastebin.com/KCeKv1pG
var selectedDivs = new Array();
canvas.innerHTML += "<div id="+currDev+" class='DRAGGABLE' onClick='addBorder(this)>" + "<img src='/devices/" + device + ".gif'></img></div>";
function addBorder(e) {
if (ctrlBeingpressed == true) {
selectedDivs.push(e);
e.style.border = "2px dotted black";
}
}
function deleteSelected() {
console.log(selectedDivs);
var len = selectedDivs.length;
for (var i = 0, len; i < len; i++){
console.log("before html remove: " + selectedDivs.length);
var node = selectedDivs[i];
node.parentNode.removeChild(node);
console.log("after html remove: " + selectedDivs.length);
for (var i in racks)
{
console.log(i);
if(node.id == racks[i].refdev)
{
console.log("Found in rack");
for (z = 1; z < racks[i].punkt.length; z++)
{
if(racks[i].punkt[z] != undefined)
{
if(racks[i].punkt[z].y.indexOf("S") > -1) //If it's an already defined point at an S card
{
//Clearing the TD
$("#sTab tr:eq("+(cardsS.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").html(" ");
$("#sTab tr:eq("+(cardsS.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").css("background-color","#E6E6E6");
}
else // Then it must be a P or V card
{
$("#pvTab tr:eq("+(cardsPV.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").html(" ");
$("#pvTab tr:eq("+(cardsPV.indexOf(racks[i].punkt[z].y)+1)+") td:eq("+(racks[i].punkt[z].x-1)+")").css("background-color","#E6E6E6");
}
}
}
console.log("Found in rack, breaking this loop");
delete racks[i];
break;
}
}
}
As discussed in the comments, there's a problem with resetting the value of the i variable within the nested loop. I took the liberty of editing the code to the way I would write it. I jQueried up some things since you're already using it anyway. (This code assumes you can target IE 9 or later and thus use Array.prototype.forEach and also that racks is an array, which seemed to be the case from the original.)
var selectedDivs = [];
$(canvas).append("<div id="+currDev+" class='DRAGGABLE' onClick='markSelected(this)'><img src='/devices/" + device + ".gif'></img></div>");
function markSelected(div) {
if (ctrlBeingpressed == true) {
selectedDivs.push(div);
$(div).css("border", "2px dotted black");
}
}
function deleteSelected() {
var i, z, deletedDivIDs = [];
console.log(selectedDivs);
selectedDivs.forEach(function(selectedDiv, index, selectedDivs) {
console.log("Removing", selectedDiv, "at index", index);
divIDs.push(selectedDiv.id);
selectedDiv.parentNode.removeChild(selectedDiv);
});
racks.forEach(function(rack, index, racks) {
console.log(i);
if(deletedDivIDs.indexOf(rack.refdev) !== -1) {
console.log("Found in rack");
for (z = 1; z < rack.punkt.length; z++) {
if(rack.punkt[z] !== undefined) {
if(rack.punkt[z].y.indexOf("S") > -1) {//If it's an already defined point at an S card
//Clearing the TD
$("#sTab tr:eq("+(cardsS.indexOf(rack.punkt[z].y)+1)+") td:eq("+(rack.punkt[z].x-1)+")").css("background-color","#E6E6E6").empty();
}
else { // Then it must be a P or V card
$("#pvTab tr:eq("+(cardsPV.indexOf(rack.punkt[z].y)+1)+") td:eq("+(rack.punkt[z].x-1)+")").css("background-color","#E6E6E6").empty();
}
}
}
racks[rack] = undefined;
}
});
}
I didn't have a chance to test this in real code since we still don't know what racks looks like, but hopefully this gets you further down the road.
you have created nested for loops with the same var i=0, It could be your problem.
And the other point I like to point out is, if racks is an array you'd better not use for(var i in racks) because it would scan all other prototype attributes in your Array.prototype, which depends on what libraries you have used in your page. and If racks is not an array, it would scan all other properties in your Object.prototype, what I mean is, if it is just a iteration using for(var i in racks) is not safe, because adding a new Javascript library could mess with your code.

Need a better way to mass modifying css Class

I have a huge collection of list elements.
the concept is that the user can select only two items from that collection.
I am showing a check/Uncheck as an image infront of the list item, just for visual purposes that the list is selected or not.
The image is defined in a class, so I have to switch classes to show selected or unselected.
This is they way I am currently modifying the class but I think it might be too heavy.
function showAsSelected(selectedArr, selectedCat) {
var allLinks = document.getElementsByClassName("linkRef");
var len = allLinks.length;
for (var i = 0; i < len; i++) {
allLinks[i].setAttribute('class', 'linkRef subCategLink');
}
for (var i = 0; i < selectedArr.length; i++) {
selectedArr[i].setAttribute('class', 'linkRef subCategLinkChkd');
}
}
'allLinks' gets all the elements having class "linkRef". counting above 100 sometimes. The first loop modifies class to 'linkRef subCategLink'. This means it will remove 'subCategLinkChkd' from two elements (Running a loop on hundreds only to modify two).
The second loop sets the class only on the two elements which are referenced in the "selectedArr" array.
I assuming that you have a similar HTML structure (and if so) you can try something like this.
jsFiddle
(function () {
"use strict";
var list = document.getElementById("list"),
selectedInputs = [],
shifted = null;
list.addEventListener("change", function (e) {
var target = e.target,
index = selectedInputs.indexOf(target);
if (target.nodeName.toLowerCase() === "input" &&
target.type.toLowerCase() === "checkbox" &&
target.classList.contains("linkRef")) {
if (target.checked && index === -1) {
target.setAttribute('class', 'linkRef subCategLinkChkd');
selectedInputs.push(target);
} else if (target.checked === false && index !== -1) {
selectedInputs.splice(index, 1);
target.setAttribute('class', 'linkRef subCategLink');
}
if (selectedInputs.length > 2) {
shifted = selectedInputs.shift();
shifted.setAttribute('class', 'linkRef subCategLink');
shifted.checked = false;
}
}
}, false);
}());
Updated

two delimiters output formatting javascript

I thought this would be easier, but running into a weird issue.
I want to split the following:
theList = 'firstword:subwordone;subwordtwo;subwordthree;secondword:subwordone;thirdword:subwordone;subwordtwo;';
and have the output be
firstword
subwordone
subwordtwo
subwordthree
secondword
subwordone
thirdword
subwordone
subwordtwo
The caveat is sometimes the list can be
theList = 'subwordone;subwordtwo;subwordthree;subwordfour;'
ie no ':' substrings to print out, and that would look like just
subwordone
subwordtwo
subwordthree
subwordfour
I have tried variations of the following base function, trying recursion, but either get into infinite loops, or undefined output.
function getUl(theList, splitOn){
var r = '<ul>';
var items = theList.split(splitOn);
for(var li in items){
r += ('<li>'+items[li]+'</li>');
}
r += '</ul>';
return r;
}
The above function is just my starting point and obviously doesnt work, just wanted to show what path I am going down, and to be shown the correct path, if this is totally off base.
It seems you need two cases, and the difference between the two is whether there is a : in your string.
if(theList.indexOf(':') == -1){
//Handle the no sublist case
} else {
//Handle the sublist case
}
Starting with the no sublist case, we develop the simple pattern:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
//Add your element to your list
}
Finally, we apply that same pattern to come up with the implementation for the sublist case:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
if(element.indexOf(':') == -1){
//Add your simple element to your list
} else {
var innerElements = element.split(':');
//Add innerElements[0] as your parent element
//Add innerElements[1] as your child element
//Increment i until you hit another element with ':', adding the single elements each increment as child elements.
//Decrement i so it considers the element with the ':' as a parent element.
}
}
Keep track of the current list to add items to, and create a new list when you find a colon in an item:
var baseParent = $('ul'), parent = baseParent;
$.each(theList.split(';'), function(i, e) {
if (e.length) {
var p = e.split(':');
if (p.length > 1) {
baseParent.append($('<li>').append($('<span>').text(p[0])).append(parent = $('<ul>')));
}
parent.append($('<li>').text(p[p.length - 1]));
}
});
Demo: http://jsfiddle.net/Guffa/eWQpR/
Demo for "1;2;3;4;": http://jsfiddle.net/Guffa/eWQpR/2/
There's probably a more elegant solution but this does the trick. (See edit below)
function showLists(text) {
// Build the lists
var lists = {'': []};
for(var i = 0, listKey = ''; i < text.length; i += 2) {
if(text[i + 1] == ':') {
listKey = text[i];
lists[listKey] = [];
} else {
lists[listKey].push(text[i]);
}
}
// Show the lists
for(var listName in lists) {
if(listName) console.log(listName);
for(var j in lists[listName]) {
console.log((listName ? ' ' : '') + lists[listName][j]);
}
}
}
EDIT
Another interesting approach you could take would be to start by breaking it up into sections (assuming text equals one of the examples you gave):
var lists = text.match(/([\w]:)?([\w];)+/g);
Then you have broken down the problem into simpler segments
for(var i = 0; i < lists.length; i++) {
var listParts = lists[i].split(':');
if(listParts.length == 1) {
console.log(listParts[0].split(';').join("\n"));
} else {
console.log(listParts[0]);
console.log(' ' + listParts[1].split(';').join("\n "));
}
}
The following snippet displays the list depending on your requirements
var str = 'subwordone;subwordtwo;subwordthree;';
var a = []; var arr = [];
a = str;
var final = [];
function split_string(a){
var no_colon = true;
for(var i = 0; i < a.length; i++){
if(a[i] == ':'){
no_colon = false;
var temp;
var index = a[i-1];
var rest = a.substring(i+1);
final[index] = split_string(rest);
return a.substring(0, i-2);
}
}
if(no_colon) return a;
}
function display_list(element, index, array) {
$('#results ul').append('<li>'+element+'</li>');
}
var no_colon_string = split_string(a).split(';');
if(no_colon_string){
$('#results').append('<ul><ul>');
}
no_colon_string.forEach(display_list);
console.log(final);
working fiddle here

sort unordered list of buttons by list.id

My html5, css, javascript program will be a day calendar. Clicking on the button of an event will bring up the details of that event. Right now, I have a days worth of events in the order they were entered. I'm stuck trying to sort an unordered list of buttons based on their id. Here you can see how each ul button is created. Values come from an indexedDB.
function renderTodo(row) {
var todos = document.getElementById("todoItems");
var li1 = document.createElement("li");
var name = document.createTextNode(row.name);
var li2 = document.createElement("li");
var time = document.createTextNode(row.time);
var btn = document.createElement("BUTTON")
var a = document.createElement("a");
var li = document.createElement("li");
a.addEventListener("click", function() {
helicopter.indexedDB.deleteEvent(row.timeStamp);
}, false);
a.textContent = " [Delete]";
li1.appendChild(name);
li2.appendChild(time);
btn.onclick=viewEvent;
btn.id=row.parent;
btn.row = row;
btn.appendChild(li1);
btn.appendChild(li2);
li.appendChild(btn);
li.appendChild(a);
li.id = row.time;
todos.appendChild(li)
sortUnorderedList(todos);
}
In other words, the finished product looks something like this.
ul-button2-[delete]
ul-button1-[delete]
ul-button3-[delete]
When I convert the list to array, it drops the button and only keeps the two li values. I've tried a few things to no success (see below). Should I drop the button idea and just use CSS to give the same look or is there a good way to sort the buttons.
function sortUnorderedList(ul) {
//if(typeof ul == "string")
//ul = document.getElementById(ul);
// Idiot-proof, remove if you want
if(!ul) {
alert("The UL object is null!");
return;
}
// Get the list items and setup an array for sorting
var lis = ul.getElementsByTagName("LI");
var ali = Array.lis;
ali.sort(liSort);
ul.innerHTML = "";
// Populate the array
for(var i = 0, j = lis.length; i < 2; i++)
ul.appendChild(ali[i]);
// Sort it
//vals.sort(liSort);
//vals.reverse();
// Change the list on the page
//for(var i = 0, l = lis.length; i < l; i++)
//lis[i].innerHTML = vals[i];
}
function liSort(one, two) {
//alert(one.id + " - " two.id);
return one.id - two.id;
}
1.) Because the lis (which should be sorted) have sub-lis, it will be better to select them by class (which is available with html5); so add a class with following line after li.id = row.time;:
li.className = 'sortLi';
2.) In the function select them and convert the list to an array:
var lis = ul.getElementsByClassName("sortLi");
var ali = Array.prototype.slice.call(lis);
3.) Append them now in sorted order:
ali.sort(liSort);
for (var i = 0; i < ali.length; i++) {
ul.appendChild(ali[i]);
}
4.) The sort function:
function liSort(one, two) {
return one.id < two.id ? -1 : ( one.id > two.id ? 1 : 0 );
}
Also see an example.

Self referencing list items in html for ordered lists

Is there a way to have a self referencing 'list item' in html so when I reference a number or letter in an ordered list it keeps track of changes. Therefore, when I add or remove list items it automatically change the references to update to the new ordered list number or letter.
If this type of self referencing is not possible in older html versions how about in html5?
Also is this type of referencing available in javascript or a javascript framework like jQuery?
Given HTML like
<ol title="Figure 1">
<li id="poundcake">Pound Cake</li>
<li id="spongecake">Sponge Cake</li>
</ol>
<p>The most delicious from the list above is <label for="spongecake">.</p>
and then at the bottom (or onload),
<script>(function () {
// From http://stackoverflow.com/questions/5395177/ordered-list-index
function itemIndex(listItem) {
var index = 0;
for (var sibling = listItem; sibling;
sibling = sibling.previousSibling) {
if (sibling.tagName == "LI") {
var value = +sibling.value;
if (value) {
return value + index;
}
++index;
}
}
var start = +listItem.parentNode.start || 1;
return start + index - 1;
}
var labels = document.getElementsByTagName("label");
for (var i = 0, n = labels.length; i < n; ++i) {
var label = labels[i];
var id = label.getAttribute("for");
if (!id) { continue; }
var target = document.getElementById(id);
if (!target || target.tagName !== "LI") { continue; }
var replacementText = (target.parentNode.title || "")
+ " item " + itemIndex(target);
label.parentNode.replaceChild(
document.createTextNode(replacementText), label);
}
}())</script>
Maybe this will help: Ordered List Index

Categories