I am attempting to loop through a very simple array in order to create a menu. I have been all around the solution, but have yet to nail it down.
Here's my script:
var json_data = [["Womens","/womens"],["Best Sellers","/best-sellers"]];
var json_length = json_data.length;
var inner_length = 0;
for (var i = 0; i<json_length; i++)
{
inner_length = json_data[i].length;
for( var j = 0; j<inner_length; j++ ){
var innerData = json_data[i][j];
var data = '' + json_data[j][0] + '<br/>';
//alert(data);
$("#content").append(data);
}
}
Basic HTML:
<div id="content">
</div>
When I move the code to append to my div within the first for loop (rather than the second), the second object's data is shown twice rather than the first then second. The current code shows both the first and second object's data, but duplicates it due to being inside the second for loop. I'm sure there is a simple solution, but I am at a loss of ideas.
You can iterate through the array more easily using forEach():
json_data.forEach(function(item) {
var data = '' + item[0] + '<br/>';
$("#content").append(data);
});
Fiddle
Updated your fiddle, removed the unnecessary loop:
https://jsfiddle.net/79k32o1j/4/
for (var i = 0; i<json_length; i++) {
var data = '' + json_data[i][0] + '<br/>';
$("#content").append(data);
}
Related
I am trying to increment the delay of every data-attribute inside the div element.
See my code
JQUERY
jQuery(document).ready(function($) {
var Column = [], startDelayTime, counter;
Column = $('.col-outside');
startDelayTime = 300;
addDelayTime = 25;
for(var i = 0; i < Column.length; i++) {
Column.attr('data-sal-delay', startDelayTime + addDelayTime[i]);
}
});
HTML:
<div class="col-md-3 col-outside" data-sal="slide-right" data-sal-easing="ease-out-bounce" data-sal-delay="300">
Hopefully someone can explain me what i am doing wrong, or what i have to do.
The logic in your loop needs to look like this. I removed the JQuery logic to simplify the example.
var currentDelay = 300;
var addDelayTime = 25;
for(var i = 0; i < 10; i++) {
// Column.attr('data-sal-delay', currentDelay);
console.log(currentDelay);
currentDelay += addDelayTime;
}
This will work:
You need to multiply by i on delayStart to get desired effect.
$(function() {
var Column = [], startDelayTime, counter;
Column = $('.col-outside');
startDelayTime = 300;
addDelayTime = 25;
Column.each(function(i, c){
$(c).attr('data-sal-delay', startDelayTime+ (addDelayTime*i));
});
});
You need to do two things:
Use the current column in your loop (Column[i] rather than Column).
Increment the value of startDelayTime every time the loop iterates.
Here's your edited code:
jQuery(document).ready(function($) {
var Column = [], startDelayTime, counter;
Column = $('.col-outside');
startDelayTime = 300;
addDelayTime = 25;
for(var i = 0; i < Column.length; i++) {
Column[i].attr('data-sal-delay', startDelayTime + addDelayTime);
startDelayTime += addDelayTime;
}
});
Now your code should work. Hopefully this helps!
There are a few problems with your code.
Within your loop, you need to access the single column node using Column[i] in order to set an attribute.
attr() is a jQuery method, so you need to use it on a jQuery selection like $(Column[i]).attr(name, value). Or you could just use the javascript method setAttribute like Column[i].setAttribute(name, value)
addDelayTime is an integer so addDelayTime[i] is undefined. What you want to do here instead is multiply addDelayTime by the current array index. addDelayTime * i
In this example I've fixed the above 3 issues and instead of a for loop I've used jQuery's each to iterate over the columns.
jQuery(document).ready(function($) {
var startDelayTime = 300;
var addDelayTime = 25;
$.each($(".col-outside"), function(index, item) {
$(item).attr("data-sal-delay", startDelayTime + index * addDelayTime);
});
});
.col-outside::after {
content: attr(data-sal-delay);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-outside"></div>
<div class="col-outside"></div>
<div class="col-outside"></div>
<div class="col-outside"></div>
<div class="col-outside"></div>
I have a for loop which looks like this:
for (var i = 0; i < list.length; i++) {
It is looping through Firebase data in the database and returning all the data in the database.
However, I want it to only go up to the first 10 database items. So I changed the loop to:
for (var i = 0; i < 9; i++) {
But this fails to display any results when the there are less than 10 pieces of data in the database. However, if I set the number to however many objects I have in the database, for example 10 because I have 10 objects, it displays them all. But any less than this number and I just get a blank webpage.
Here is the webpage when I have 10 objects in my Firebase database:
And here it is when I remove one of those objects:
I have no idea why this is happening - The logic is correct - if i is less than 9 then display the data - But instead it only displays it when it equals 9.
Here is the full JS:
function refreshUI(list) {
var lis = '';
var lis2 = '';
var lis3 = '';
var lis4 = '';
for (var i = 0; i <= 9; i++) {
lis += '<li data-key="' + list[i].key + '" onclick="addText(event)">' + list[i].book + '</li>';
lis2 += genLinks(list[i].key, list[i].book)
};
for (var i = 10; i < list.length; i++) {
lis3 += '<li data-key="' + list[i].key + '" onclick="addText(event)">' + list[i].book + '</li>';
lis4 += genLinks(list[i].key, list[i].book)
};
document.getElementById('bookList').innerHTML = lis;
document.getElementById('bookList2').innerHTML = lis2;
document.getElementById('bookList3').innerHTML = lis3;
document.getElementById('bookList4').innerHTML = lis4;
};
function genLinks(key, bkName) {
var links = '';
links += '<img src="images/bin.png" style="width: 24px; height: 24px; transform: translateY(-7px); opacity: .4;"></img> ';
return links;
};
function del(key, bkName) {
var response = confirm("Are certain about removing \"" + bkName + "\" from the list?");
if (response == true) {
// build the FB endpoint to the item in movies collection
var deleteBookRef = buildEndPoint(key);
deleteBookRef.remove();
}
}
function buildEndPoint (key) {
return new Firebase('https://project04-167712.firebaseio.com/books/' + key);
}
// this will get fired on inital load as well as when ever there is a change in the data
bookList.on("value", function(snapshot) {
var data = snapshot.val();
var list = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
book = data[key].book ? data[key].book : '';
if (book.trim().length > 0) {
list.push({
book: book,
key: key
})
}
}
}
// refresh the UI
refreshUI(list);
});
If anybody has any help I'd greatly appreciate it!
When the list size is shorter than 10, you will get an error in the loop because you will eventually address a property (like key) that does not exist on list[i] (since it is undefined). If you would check the console, you would notice that this error is reported.
To fix this, change the condition of the first for loop like this:
for (var i = 0; i < Math.min(10, list.length); i++) {
This way, the loop will never iterate to an entry that does not exist. It will stop after 9 or after list.length-1 whichever comes first.
Alternatively, you can just put the two conditions with an && operator:
for (var i = 0; i < 10 && i < list.length; i++) {
Update: I've tried the suggestions in the comments and it's still not working. I really have no idea why. I've consolidated it to a single loop and fixed the syntax errors noted. Here's the code as it looks now:
$(function() {
$("#json-one").change(function() {
var $dropdown = $(this);
$.getJSON("washroutines.json", function(data) {
var vals = [];
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
$jsontwo.append("<option value=\"" + data[i].model + "\">" + data[i].model + "</option>");
}
}
});
});
});
Any additional help would be much appreciated!
Original question:
I'm trying to create dependent drop down menus using a json object, and I'm having trouble getting the second menu to populate based on the first. When the first menu changes, the second goes to a bunch of "undefined"s.
$.getJSON("washroutines.json", function(data) {
var vals = [];
for (i = 0; i < data.length; i++){
if (data.make = $dropdown.val()) {
vals.push(data.model);
}
}
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (i = 0; i < vals.length; i++){
$jsontwo.append("<option value\"" + vals[i] + "\">" + vals[i] + "</option>");
}
Please use small words when explaining things to me, I'm new at this!
contents of the JSON:
[{"make":"Maytag","model":"Bravos","prewashCycle":"Whitest Whites"},
{"make":"Maytag","model":"Awesome","prewashCycle":"Awesome Whitest Whites"},
{"make":"Whirlpool","model":"Cabrio","prewashCycle":"Extra Heavy"},
{"make":"Kenmore","model":"Elite","prewashCycle":"Awesome"}]
Try changing your for loop for this
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
vals.push(data[i].model);
}
}
This is a really simple question but I don't know why it doesn't work.
I have an array with 3 items inside. And I have a container which I would like to insert a number of divs based on the number of items in my array. I used a for loop for this but it is only creating one div. Should it not create 3?
for (var i = 0; i < array.length; i++) {
var container = document.getElementById("container");
container.innerHTML = '<div class="box"></div>';
}
here is a fiddle to demonstrate further fiddle
Move container out of the loop, it is not required inside it.
Append the innerHTML in each iteration.
var container = document.getElementById("container");
for (var i = 0; i < array.length; i++) {
container.innerHTML += '<div class="box"></div>';
}
Edit:
Thanks Canon, for your comments. I also wanted to suggest the same approach as yours, but I got busy in some other work after posting the answer [No excuses :)] Updating the answer:
var htmlElements = "";
for (var i = 0; i < array.length; i++) {
htmlElements += '<div class="box"></div>';
}
var container = document.getElementById("container");
container.innerHTML = htmlElements;
This may look like involving more lines of code but this will be more efficient and less error-prone than the previous solution.
Replace = to +=
As per the #canon comment, edited answer are below
var innerHTMLString = "";
forloop {
innerHTMLString += '<div class="box"></div>';
}
document.getElementById("htmlElements").innerHTML = innerHTMLString
Replace this
container.innerHTML = '<div class="box"></div>';
with this
container.innerHTML += '<div class="box"></div>';
If you want to create more than one, you must call createElement more than once.
d=document.createElement("div");
line into the j loop.
If you call appendChild passing in an element that's already in the DOM, it's moved, not copied.
window.onload=function()
{
var i=0;
var j=0;
for (i=1; i<=8; i++)
{
for (j=1; j<=8; j++)
{
if ((i%2!=0 && j%2==0)||(i%2==0 && j%2!=0))
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="black";
}
else
{
var d=document.createElement("div");
document.body.appendChild(d);
d.className="white";
}
}
}
}
Javascript Method -
var container = document.getElementById("container");
for (var i = 0; i < array.length; i++) {
container.innerHTML += '<div class="box"></div>';
}
jQuery Method -
foreach(array as value){
$("#container").append('<div class="box"></div>')
}
For further references; what about this approach? :)
HTML:
<div class="particles">
<div class="parts"></div>
</div>
JavaScript:
// Cloning divs where particles go in order not to put 300 of them in the markup :)
const node = document.querySelector(".parts");
[...Array(300)].forEach(_ =>
node.parentNode.insertBefore(node.cloneNode(true), node)
);
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