How do I loop over an Array which has 5 elements. I have 5 elements with ids like imgone, imgtwo, imgthree, imgfour, imgfive.
var ids =
[
"#imgone",
"#imgtwo",
"#imgthree",
"#imgfour",
"#imgfive"
];
for (var i = 0; id = ids[i]; i++)
{
$(id).click(function() {
$("#cell1,#cell2,#cell3,#cell4,#cell5").hide();
$("#cell" + (i+1)).show();
});
}
});
Then I have an 5 a tag elements like
<img src ="myimage1" />
<img src ="myimage2" />
<img src ="myimage3" />
<img src ="myimage4" />
<img src ="myimage5" />
cell1 , cell2, et-al are my blocks that I need to show/hide onclick of a elements.
btw this code always hides all the cell blocks and shows cell6, which does not exist in my code.
I mean $("#cell" + (i+1)).show(); never takes values of i as 0, 1 , 2 , 3 or 4.
So how do I iterate over an array and show hide my cells. I think something is wrong with this line of code $(id).click(function() but can't figure out what???
This is a closure issue, the variable i points to the i used in the loop, and at the time of execution it is always 6.
use this code instead
for (var i = 0; id = ids[i]; i++)
{
var fnc = function(j){
return function() {
$("#cell1,#cell2,#cell3,#cell4,#cell5").hide();
$("#cell" + (j+1)).show();
};
}(i);
$(id).click(fnc);
}
For more on javascript closures see How do JavaScript closures work?
you could jquerify it :
var ids =
[
"#imgone",
"#imgtwo",
"#imgthree",
"#imgfour",
"#imgfive"
];
$(ids.join(,)).each(function(i){
$(this).click(function(){
$("#cell1,#cell2,#cell3,#cell4,#cell5").hide();
$("#cell" + (i+1)).show();
});
});
Related
Since my last question, I've decided to reveal images individually. However, now I'm having an issue with the sequence. With what I've written so far, it seems that my second needed image (stack2.PNG) appears before the first (stack1.PNG). Also, I'm not too sure how to go about ending the function after the final image (stack3.PNG).
Here's what I have so far:
<body>
<input type=button value="Produce Stipends" onclick="nextStack()"/>
<img id="stipends" src="nostack.PNG">
</body>
<script>
var stipends = document.getElementById("stipends");
var stack = ["stack1.PNG", "stack2.PNG", "stack3.PNG"];
var currentStack = 0;
stack.forEach(function(src) {
new Image().src = src;
});
function nextStack() {
currentStack++;
currentStack > 2 && (currentStack = 0);
stipends.src = stack[currentStack];
}
</script>
Also, if it's not too much to ask, how would I go about changing the name of the button once the sequence is over and linking to another page.
Thanks in advance!
Run the below code if you want to output a single index of the stack array on each click.
EDIT: Included comments in code.
var stipends = document.getElementById("stipends");
var stack = ["stack1.PNG", "stack2.PNG", "stack3.PNG"];
//currentStack = 0 starts the index at 0
//we will use this to iterate over the array in sequential order starting with the first item
var currentStack = 0;
function nextStack() {
//declare array length as a var
var len = stack.length;
//on click, check if currentStack value is less than len
if(currentStack < len){
//console log the item in the stack array that has a matching index
console.log(stack[currentStack]);
//apply the same output as image source
stipends.src = stack[currentStack];
//continue adding to the currentStack for the next loop until finished
currentStack++;
}
}
<input type=button value="Produce Stipends" onclick="nextStack()" />
<img id="stipends" src="nostack.PNG">
Is this what you're trying to do?
var stipends = document.getElementById("stipends");
var stack = ["stack1.PNG", "stack2.PNG", "stack3.PNG"];
var currentStack = 0;
function nextStack() {
currentStack++;
stipends.src = stack[currentStack];
if (currentStack > stack.length) {
currentStack = 0;
}
}
<input type="button" value="Produce Stipends" onclick="nextStack()"/>
<img id="stipends" src="nostack.PNG">
I'm creating a Time table generating website as a part of my project and I am stuck at one point.
Using for loop, I am generating user selected text boxes for subjects and faculties. Now the problem is that I cannot get the values of those dynamically generated text boxes. I want to get the values and store it into array so that I can then later on store it to database
If I am using localstorage, then it sometimes shows NaN or undefined. Please help me out.
Following is my Jquery code
$.fn.CreateDynamicTextBoxes = function()
{
$('#DynamicTextBoxContainer, #DynamicTextBoxContainer2').css('display','block');
InputtedValue = $('#SemesterSubjectsSelection').val();
SubjectsNames = [];
for (i = 0; i < InputtedValue; i++)
{
TextBoxContainer1 = $('#DynamicTextBoxContainer');
TextBoxContainer2 = $('#DynamicTextBoxContainer2');
$('<input type="text" class="InputBoxes" id="SubjectTextBoxes'+i+'" placeholder="Subject '+i+' Name" style="margin:5px;" value=""><br>').appendTo(TextBoxContainer1);
$('<input type="text" class="InputBoxes" id="FacultyTextBoxes'+i+'" placeholder="Subject '+i+' Faculty Name" style="margin:5px;" value=""><br>').appendTo(TextBoxContainer2);
SubjectsNames['SubjectTextBoxes'+i];
}
$('#DynamicTextBoxContainer, #UnusedContainer, #DynamicTextBoxContainer2').css('border-top','1px solid #DDD');
}
$.fn.CreateTimeTable = function()
{
for (x = 0; x < i; x++)
{
localStorage.setItem("Main"+x, +SubjectsNames[i]);
}
}
I am also posting screenshot for better understanding
I understand you create 2 text boxes for each subject, one for subject, and second one for faculty. And you want it as a jQuery plugin.
First of all, I think you should create single plugin instead of two, and expose what you need from the plugin.
You should avoid global variables, right now you have InputtedValue, i, SubjectsNames, etc. declared as a global variables, and I believe you should not do that, but keep these variables inside you plugin and expose only what you really need.
You declare your SubjectNames, but later in first for loop you try to access its properties, and actually do nothing with this. In second for loop you try to access it as an array, but it's empty, as you did not assign any values in it.
Take a look at the snippet I created. I do not play much with jQuery, and especially with custom plugins, so the code is not perfect and can be optimized, but I believe it shows the idea. I pass some selectors as in configuration object to make it more reusable. I added 2 buttons to make it more "playable", but you can change it as you prefer. Prepare button creates your dynamic text boxes, and button Generate takes their values and "print" them in result div. generate method is exposed from the plugin to take the values outside the plugin, so you can do it whatever you want with them (e.g. store them in local storage).
$(function() {
$.fn.timeTables = function(config) {
// prepare variables with jQuery objects, based on selectors provided in config object
var numberOfSubjectsTextBox = $(config.numberOfSubjects);
var subjectsDiv = $(config.subjects);
var facultiesDiv = $(config.faculties);
var prepareButton = $(config.prepareButton);
var numberOfSubjects = 0;
prepareButton.click(function() {
// read number of subjects from the textbox - some validation should be added here
numberOfSubjects = +numberOfSubjectsTextBox.val();
// clear subjects and faculties div from any text boxes there
subjectsDiv.empty();
facultiesDiv.empty();
// create new text boxes for each subject and append them to proper div
// TODO: these inputs could be stored in arrays and used later
for (var i = 0; i < numberOfSubjects; i++) {
$('<input type="text" placeholder="Subject ' + i + '" />').appendTo(subjectsDiv);
$('<input type="text" placeholder="Faculty ' + i + '" />').appendTo(facultiesDiv);
}
});
function generate() {
// prepare result array
var result = [];
// get all text boxes from subjects and faculties divs
var subjectTextBoxes = subjectsDiv.find('input');
var facultiesTextBoxes = facultiesDiv.find('input');
// read subject and faculty for each subject - numberOfSubjects variable stores proper value
for (var i = 0; i < numberOfSubjects; i++) {
result.push({
subject: $(subjectTextBoxes[i]).val(),
faculty: $(facultiesTextBoxes[i]).val()
});
}
return result;
}
// expose generate function outside the plugin
return {
generate: generate
};
};
var tt = $('#container').timeTables({
numberOfSubjects: '#numberOfSubjects',
subjects: '#subjects',
faculties: '#faculties',
prepareButton: '#prepare'
});
$('#generate').click(function() {
// generate result and 'print' it to result div
var times = tt.generate();
var result = $('#result');
result.empty();
for (var i = 0; i < times.length; i++) {
$('<div>' + times[i].subject + ': ' + times[i].faculty + '</div>').appendTo(result);
}
});
});
#content div {
float: left;
}
#content div input {
display: block;
}
#footer {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
<div id="header">
<input type="text" id="numberOfSubjects" placeholder="Number of subjects" />
<button id="prepare">
Prepare
</button>
</div>
<div id="content">
<div id="subjects">
</div>
<div id="faculties">
</div>
</div>
</div>
<div id="footer">
<button id="generate">Generate</button>
<div id="result">
</div>
</div>
I have a table of 4 images that change on click. I was wondering how I could check to see if/when all images in the table are the same image source. I am stuck trying to figure out a way to check all image sources in the table. Any advice is appreciated!
HTML:
<table>
<tr>
<td>
<img id="pos1" src="slicedImg_01.gif" onclick="change(1)" />
<img id="pos2" src="slicedImg_02.gif" onclick="change(2)" />
</td>
<tr>
<td>
<img id="pos3" src="slicedImg_03.gif" onclick="change(3)" />
<img id="pos4" src="slicedImg_04.gif" onclick="change(4)" />
</td>
</tr>
</tr>
</table>
JS:
var v = document.getElementById("pos" + clicked_img).src = "slicedImg_0" + rNum + ".gif";
//var elems = document.getElementsByName.images("f")[0].src;
//alert(elems);
if (document.getElementById("pos1").src == v){
if (document.getElementById("pos2").src == v){
if (document.getElementById("pos3").src == v)
Don't mind my trial and error attempts on the page.
Try running this where it makes sense, the src parameter can be removed if the matching src you're looking to check is static.
function checkSameSrc(src){
return document.querySelector('src=[" + src + "]').length === 4;
}
If jQuery is allowed, a quick Fiddle as example:
var image_array = $("img").map(function () {
return $(this).attr("src");
});
images = $.unique(image_array);
alert(images.length);
In case images.length is 1, there's only 1 unique image source. When you change one of the image sources in the fiddle to one of the other images and run the fiddle again, the alert will give you 3 instead of 4 etc.
image_array is created using the map()-function, pushing the src of each image into the array. The unique()-function removes all double entries from this array.
References: http://api.jquery.com/jquery.unique/, http://api.jquery.com/jquery.map/
And the same with pure Javascript:
var elements = document.getElementsByTagName('img');
var imageArray = new Array();
for (var i=0; i<elements.length; i++) {
imageArray[i] = new Image();
imageArray[i] = elements[i].src;
}
function getUnique(element)
{
return element.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);
}
alert(getUnique(imageArray).length);
Fiddle with both versions and one double image: Fiddle
Reference for the nice one-liner used in getUnique(): Remove Duplicates from JavaScript Array, see answer by Christian Landgren.
So I have set up two javascript arrays to pull information from some php. One array gets the name of the category to be clicked on, while the other array stores the class and id tag for the category. The class and id tags are the same other than there css type, but the array needs to output them into document elements and then, when clicked, affect the relevant areas of the document. I also need to remove duplicates from the arrays, which doesn't seem to work under my current code:
<script type="text/javascript">
var BookSeries = [];
var BookClass = [];
var i=0;
</script>
then variables for the array are pulled from php and output this way:
<script type="text/javascript">
var uniqueSeries = BookSeries.filter(function(elem, pos) {
return BookSeries.indexOf(elem) == pos;
});
var uniqueClass = BookClass.filter(function(elem, pos) {
return BookClass.indexOf(elem) == pos;
});
while (uniqueSeries[i]) {
document.write( "<span id='"+uniqueClass[i]+"'>"+uniqueSeries[i]+"</span>" );
i++;
}
for(var i = 0; i < uniqueClass.length; i++) {
$np("#"+uniqueClass[i]).click(function(){
$np(".postitem").fadeOut(200);
$np("."+uniqueClass[i]).fadeIn(200);
});
}
</script>
You are using jquery so you can do the following for appending the elements to the DOM:
var htmlString = "";
for (var i = 0; i < uniqueSeries.length; i++) {
htmlString += "<span id='"+uniqueClass[i]+"'>"+uniqueSeries[i]+"</span>";
}
$("#myContainer").html(htmlString);
Not sure what is $np so I'll assume you meant jquery's $.
for(var i = 0; i < uniqueClass.length; i++) {
var uClass = uniqueClass[i];
$("#" + uClass).click(function(){
$(".postitem").fadeOut(200);
$("." + uClass).fadeIn(200);
});
}
Edit:
"#myContainer" refers to the id of the dom element you want to append the html to. if you just want to append it to document you can do:
$(document).appendTo(htmlString);
Also see I updated the code above to reflect your comments about the uniqueClass array.
folks! Today I created this script that has the following functionality:
add new items to array
list all items from the array
remove an item from the array
There are two functions:
addToFood() - adds the value of input to the array and updates
innerHTML of div
removeRecord(i) - remove a record from the array and updates
innerHTML of div
The code includes 3 for loops and you can see it at - http://jsfiddle.net/menian/3b4qp/1/
My Master told me that those 3 for loops make the solution way to heavy. Is there a better way to do the same thing? Is it better to decrease the loops and try to use splice? Thanks in advance.
HTML
<!-- we add to our foodList from the value of the following input -->
<input type="text" value="food" id="addFood" />
<!-- we call addToFood(); through the following button -->
<input type="submit" value="Add more to food" onClick="addToFood();">
<!-- The list of food is displayed in the following div -->
<div id="foods"></div>
JavaScript
var foodList = [];
function addToFood () {
var addFood = document.getElementById('addFood').value;
foodList.push(addFood);
for (i = 0; i < foodList.length; i++) {
var newFood = "<a href='#' onClick='removeRecord(" + i + ");'>X</a> " + foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML += newFood;
}
function removeRecord (i) {
// define variable j with equal to the number we got from removeRecord
var j = i;
// define and create a new temporary array
var tempList = [];
// empty newFood
// at the end of the function we "refill" it with the new content
var newFood = "";
for (var i = 0; i < foodList.length; i++) {
if(i != j) {
// we add all records except the one == to j to the new array
// the record eual to j is the one we've clicked on X to remove
tempList.push(foodList[i]);
}
};
// make redefine foodList by making it equal to the tempList array
// it should be smaller with one record
foodList = tempList;
// re-display the records from foodList the same way we did it in addToFood()
for (var i = 0; i < foodList.length; i++) {
newFood += "<a href='#' onClick='removeRecord(" + i + ");'>X</a> " + foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML = newFood;
}
You should use array.splice(position,nbItems)
function removeRecord (i) {
foodList.splice(i, 1); // remove element at position i
var newFood = "";
for (var i = 0; i < foodList.length; i++) {
newFood += "<a href='#' onClick='removeRecord(" + i + ");'>X</a> "
+ foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML = newFood;
}
http://jsfiddle.net/3b4qp/5/
Now using JQuery:
$(function(){
$(document).on('click','input[type=submit]',function(){
$('#foods')
.append('<div>X '
+ $('#addFood').val() + '</div>');
});
$(document).on('click','.item',function(){
$(this).parent().remove();
});
});
http://jsfiddle.net/jfWa3/
Your problem isn't the arrays, your problem is this code:
node.innerHTML += newFood;
This code is very, very, very slow. It will traverse all exising DOM nodes, create strings from them, join those strings into one long string, append a new string, parse the result to a new tree of DOM nodes.
I suggest to use a framework like jQuery which has methods to append HTML fragments to existing DOM nodes:
var parent = $('#foods');
...
for (var i = 0; i < foodList.length; i++) {
parent.append( "<a href='#' onClick='removeReco..." );
That will parse the HTML fragments only once.
If you really must do it manually, then collect all the HTML in a local string variable (as suggested by JohnJohnGa in his answer) and then assign innerHTML once.
Here's some tips to, at least, make your code more portable (dunno if it will be better performance wise, but should be, since DOM Manipulation is less expensive)
Tips
First separate your event handle from the HTML
Pass the "new food" as a function paramater
Tie the array elements to the DOM using the ID
Instead of rerendering everything when something changes (using innerHTML in the list), just change the relevant bit
Benefits:
You actually only loop once (when removing elements from the array).
You don't re-render the list everytime something changes, just the element clicked
Added bonus: It's more portable.
Should be faster
Example code:
FIDDLE
HTML
<div id="eventBinder">
<!-- we add to our foodList from the value of the following input -->
<input id="addFood" type="text" value="food" />
<!-- we call addToFood(); through the following button -->
<button id="addFoodBtn" value="Add more to food">Add Food</button>
<!-- The list of food is displayed in the following div
-->
<div id="foods"></div>
</div>
JS
// FoodList Class
var FoodList = function (selectorID) {
return {
foodArray: [],
listEl: document.getElementById(selectorID),
idCnt: 0,
add: function (newFood) {
var id = 'myfood-' + this.idCnt;
this.foodArray.push({
id: id,
food: newFood
});
var foodDom = document.createElement('div'),
foodText = document.createTextNode(newFood);
foodDom.setAttribute('id', id);
foodDom.setAttribute('class', 'aFood');
foodDom.appendChild(foodText);
this.listEl.appendChild(foodDom);
++this.idCnt;
},
remove: function (foodID) {
for (var f in this.foodArray) {
if (this.foodArray[f].id === foodID) {
delete this.foodArray[f];
var delFood = document.getElementById(foodID);
this.listEl.removeChild(delFood);
}
}
}
};
};
//Actual app
window.myFoodList = new FoodList('foods');
document.getElementById('eventBinder').addEventListener('click', function (e) {
if (e.target.id === 'addFoodBtn') {
var food = document.getElementById('addFood').value;
window.myFoodList.add(food);
} else if (e.target.className === 'aFood') {
window.myFoodList.remove(e.target.id);
}
}, false);
Here is another sugestion:
function remove(arr, index) {
if (index >= arr.lenght) { return undefined; }
if (index == 0) {
arr.shift();
return arr;
}
if (index == arr.length - 1) {
arr.pop();
return arr;
}
var newarray = arr.splice(0, index);
return newarray.concat(arr.splice(1,arr.length))
}