Using .shift() to Update an Array's Elements - javascript

I'm struggling with a pretty simple issue, but I've been going over and over it and can't seem to figure out what to do.
http://jsbin.com/harokap/edit?js,output
var parkRides = [["Bumbling Boats", 20], ["Scary Cyclone", 45],
["Cloudy Crevase", 10], ["Crazy Crapshoot", 5]];
var fastPassQueue = ["Crazy Crapshoot", "Cloudy Crevase", "Bumbling Boats",
"Crazy Crapshoot"];
function writeTicket(allRides,passRides,pick){
if(pick == passRides[0]){
passRides.shift();
return function(){
alert("Lucky you! You got a Fast Pass to " + pick + "!");
};
}else{
for(var i = 0; i < allRides.length; i++){
if(pick == allRides[i][0]){
return function(){
alert("Now printing ticket for " + pick + ". Your wait time is about " + allRides[i][1] + " minutes.");
};
}
}
}
}
var rideChoice = "Crazy Crapshoot";
var ticket = writeTicket(parkRides,fastPassQueue,rideChoice);
ticket();
In that code I have an array called "fastPassQueue" that I want to update with passRides.shift() inside of the "writeTicket" function.
I want writeTicket to recognize that the first element has been removed from fastPassQueue every time I run the function (and subsequently run the else condition after the first time the function is called), but I can't figure out how to do it. I've tried adding fastPassQueue into the beginning of the function, which works IF I run the function first the original way and THEN add it into the function, but I can't figure out how to make it work from the start...
Thanks in advance for any feedback.

It's as easy as not returning a function inside a for loop, create the string instead, and always return the function
var parkRides = [
["Bumbling Boats", 20],
["Scary Cyclone", 45],
["Cloudy Crevase", 10],
["Crazy Crapshoot", 5]
];
var fastPassQueue = ["Crazy Crapshoot", "Cloudy Crevase", "Bumbling Boats", "Crazy Crapshoot"];
function writeTicket(allRides, passRides, pick) {
if (pick == passRides[0]) {
passRides.shift();
return function () {
alert("Lucky you! You got a Fast Pass to " + pick + "!");
};
} else {
var match = "";
for (var i = 0; i < allRides.length; i++) {
if (pick == allRides[i][0]) {
match = "Now printing ticket for " + pick + ". Your wait time is about " + allRides[i][1] + " minutes.";
}
}
return function () {
alert(match);
};
}
}
var rideChoice = "Bumbling Boats";
var ticket = writeTicket(parkRides, fastPassQueue, rideChoice);
ticket();
FIDDLE

Related

Passing two variables from function

I'm trying to accomplish three functions, where one gets two values from HTML-elements, one counts exponent of these values and one console.logs what the values used were and the result.
What way would function noudaArvo be able to pass both variables to other functions? I'm trying not to change other two functions.
function laskuFunktio() { //does the printing
var luku = noudaArvo("luku");
var eksp = noudaArvo("eksponentti");
console.log("Luku " + luku + " potenssiin " + eksp + " on:");
console.log(laskePotenssi(luku, eksp));
}
function noudaArvo() { //gets the values, but can't figure how to pass them out
let luku = document.getElementById("luku").value;
let eksponentti = document.getElementById("eksponentti").value;
}
function laskePotenssi() { //counts the exponent
var luku = noudaArvo("luku");
var eksponentti = noudaArvo("eksponentti");
return Math.pow(luku, eksponentti);
}
function laskuFunktio() { //does the printing
var luku = noudaArvo("luku");
var eksp = noudaArvo("eksponentti");
console.log("Luku " + luku + " potenssiin " + eksp + " on:");
console.log(laskePotenssi(luku, eksp));
}
function noudaArvo(item) { //gets the values, but can't figure how to pass them out
return document.getElementById(item).value;
}
function laskePotenssi(luku, eksp) { //counts the exponent
return Math.pow(luku, eksp);
}
If I understand what your saying correctly this may be a solution to your problem
U don't return from noudaArvo function anything
change the function to
function noudaArvo(elId) { //gets the values, but can't figure how to pass them out
return document.getElementById(elId).value;
}

For loop variable undefined in Javascript

I'm working on implementing a system where elements can be dragged and dropped to create flowcharts. My Issue is with saving the flowchart so that it could be reloaded when needed. For now I've created a method that saves all the previous data of the element onto the final array that holds only elements that are dropped on the container. But I'm getting a Trivial Error as Undefined variable on the debugging interface. Hence I'm not getting the intended output and the alert messages that I included are not being printed when the condition is met.
Code in Context
function saveFlowchart()
{
var nodes = [];
var matches = [];
var searchEles = document.getElementById("container").children;
for(var i = 0; i < searchEles.length; i++)
{
matches.push(searchEles[i]);
var idOfEl = searchEles[i].id;
if(searchEles[i].id !=null || searchEles[i].id !="")
{
var $element = $("#" + searchEles[i].id);
var dropElem = $("#" + searchEles[i].id).attr('class');
var position = $element.position();
position.bottom = position.top + $element.height();
position.right = position.left + $element.width();
alert("class:"+dropElem+"\nTop position: " + position.top + "\nLeft position: " + position.left + "\nBottom position: " + position.bottom + "\nRight position: " + position.right);
finalArray[idOfEl-1][0]= idOfEl;
finalArray[idOfEl-1][1]= dropElem;
var elId = parseInt(idOfEl);
if (dropElem == "stream ui-draggable")
{
for(var count=0;count<100;count++)
{
alert("One loop opened with count="+count);
if(createdImportStreamArray[count][0]==elId)
{
finalArray[elId-1][2]= createdImportStreamArray[count][1]; //Selected Stream from Predefined Streams
finalArray[elId-1][3]= createdImportStreamArray[count][2]; //asName
alert("createdImportStreamArray[count][0]==elId");
}
else if(createdExportStreamArray[count][0]==elId)
{
finalArray[elId-1][2]= createdExportStreamArray[count][1]; //Selected Stream from Predefined Streams
finalArray[elId-1][3]= createdExportStreamArray[count][2]; //asName
}
else if(createdDefinedStreamArray[count][0]==elId)
{
finalArray[elId-1][2]= createdDefinedStreamArray[count][1]; //Stream Name
finalArray[elId-1][3]= createdDefinedStreamArray[count][4]; //Number of Attributes
finalArray[elId-1][4]=[];
for(var f=0;f<createdDefinedStreamArray[r][4];f++)
{
finalArray[elId-1][4][f][0]=createdDefinedStreamArray[count][2][f][0]; //Attribute Name
finalArray[elId-1][4][f][1]=createdDefinedStreamArray[count][2][f][1]; // Attribute Type
}
}
alert("One loop closed with count="+count);
}
alert("Loop ended with count="+count);
}
else if (dropElem == "wstream ui-draggable")
{
ElementType="wstream";
}
// else if conditions...
alert(finalArray);
}
}
//Code to output the connection details in a json format
//The following is not affected by the above mentioned error
$(".node").each(function (idx, elem) {
var $elem = $(elem);
var endpoints = jsPlumb.getEndpoints($elem.attr('id'));
console.log('endpoints of '+$elem.attr('id'));
console.log(endpoints);
nodes.push({
blockId: $elem.attr('id'),
nodetype: $elem.attr('data-nodetype'),
positionX: parseInt($elem.css("left"), 10),
positionY: parseInt($elem.css("top"), 10)
});
});
var connections = [];
$.each(jsPlumb.getConnections(), function (idx, connection) {
connections.push({
connectionId: connection.id,
pageSourceId: connection.sourceId,
pageTargetId: connection.targetId
});
});
var flowChart = {};
flowChart.nodes = nodes;
flowChart.connections = connections;
flowChart.numberOfElements = numberOfElements;
var flowChartJson = JSON.stringify(flowChart);
//console.log(flowChartJson);
$('#jsonOutput').val(flowChartJson);
}
Debugging Interface
According to this the count variable in the for loop is undefined. I've tried taking the first statement var count=0 outside the loop declaration part and defining it in the very beginning of the method. But that simply checks for count=0 against the conditions and doesn't increment at all.
Any help in this regard will be highly appreciated as I've been working on this minor error for almost 2 days now.

Value is added by 1, but the function is still working with the old value. Why?

I try to code a TextAdeventure and I want that a value is added by one so the program can continue with the array of part2 , then part3 and so on.
The program is showing the first part (array1) correctly. Then the value is added by 1 and the program should show the second part (array2), but it is still showing part 1. The arrays are called "part1", "part2", and so on.
When I console.log the variable "partvalue", then it shows "part2", but nevertheless the function is working with "part1". Thanks for helping.
var iCounterText = 0;
var value = 1;
var partvalue = eval("part" + value);
var verzog = setInterval(function(){
if (iCounterText < partvalue.length-3) {
++iCounterText;
toggleText.insertAdjacentHTML('beforeBegin', '<br>--------------<br>' + partvalue[iCounterText]);
playaudio();
}
else {
buttonLinks.innerHTML = partvalue[partvalue.length-1];
++value;
iCounterText=0;
buttonLinks.style.visibility = "visible";
clearInterval(verzog);
}
},500);
If you move the var partvalue = eval("part" + value); inside your setInterval function, I'm sure it will work as expected.
Updated
I now changed these 3 lines (and removed var partvalue = eval("part" + value);)
if (iCounterText < value) {
toggleText.insertAdjacentHTML('beforeBegin', '<br>--------------<br>part' + value);
buttonLinks.innerHTML = "part" + value;
So now it looks like this
var iCounterText = 0;
var value = 1;
var verzog = setInterval(function(){
if (iCounterText < value) {
++iCounterText;
toggleText.insertAdjacentHTML('beforeBegin', '<br>--------------<br>part' + value);
playaudio();
}
else {
buttonLinks.innerHTML = "part" + value;
++value;
iCounterText=0;
buttonLinks.style.visibility = "visible";
clearInterval(verzog);
}
},500);

Make a div clickable in JavaScript

I am trying to dynamically make divs that are clickable. I have inserted a test function. The test function runs even though the div has not been clicked.
function displayResults(responseTxt)
{
var results = document.getElementById("results");
jsonObj = eval ("(" + responseTxt + ")");
var length = jsonObj.response.artists.length;
results.innerHTML = "Please click on an artist for more details: "
for ( var i = 0; i < length; i++)
{
var entry = document.createElement("div");
var field = document.createElement("fieldset");
entry.id = i;
entry.innerHTML = i + 1 + ". " + jsonObj.response.artists[i].name;
field.appendChild(entry);
results.appendChild(field);
//entry.addEventListener("click", idSearch(jsonObj.response.artists[i].id), false);
entry.addEventListener("click", test(), false);
}
} // end function displayResults
function test()
{
document.getElementById("results").innerHTML = "tested";
}
You are calling the test() function and passing its return value to .addEventListener(). Remove the parentheses:
entry.addEventListener("click", test, false);
So that you pass the function itself to .addEventListener().
That answers the question as asked, but to anticipate your next problem, for the line you've got commented out you'd do this:
entry.addEventListener("click",
function() {
idSearch(jsonObj.response.artists[i].id);
}, false);
That is, create an anonymous function to pass to .addEventListener() where the anonymous function knows how to call your idSearch() function with parameters. Except that won't work because when the event is actually triggered i will have the value from the end of the loop. You need to add an extra function/closure so that the individual values of i are accessible:
for ( var i = 0; i < length; i++)
{
var entry = document.createElement("div");
var field = document.createElement("fieldset");
entry.id = i;
entry.innerHTML = i + 1 + ". " + jsonObj.response.artists[i].name;
field.appendChild(entry);
results.appendChild(field);
// add immediately-invoked anonymous function here:
(function(i) {
entry.addEventListener("click",
function() {
idSearch(jsonObj.response.artists[i].id);
}, false);
})(i);
}
That way the i in jsonObj.response.artists[i].id is actually going to be the parameter i from the anonymous function which is the individual value of i from the loop at the time each iteration ran.

building a database string

I'm trying to build a database based on some arbitrary data on a website. It's complex and changes for each site so I'll spare the details. Here's basically what I'm trying to do
function level0(arg) { textarea.innerHTML += arg + ' = {'; }
function level1(arg) { textarea.innerHTML += '\n\t' + arg + ': ['; }
function level2(arg) { textarea.innerHTML += arg + ', '; }
And so on. The thing is some level1's don't have any children and I can't get the formatting right.
My three problems are as follows.
The ending commas are going to break in IE (thank you MS)
Empty level1's shouldn't be printed if they don't have any children
Closing /curly?brackets/
HERE'S A DEMO of what I have so far. Notice the ending commas, the empty sub2 which shouldn't be printed, and no closing brackets or braces
Do I need to redesign the entire thing?
Is there also a way to have this all in one function so I don't have to worry if I add another layer?
EDIT
This needs to be done in a string format, I can't build an object and then stringify it, mostly because I need to know which element I'm in the middle of adding to.
Overall it looks that you still might want to build an object, but in case you insist on not building it - here is some sample solution:
function Printer() {
var result = '',
lastLevel = null,
close = {0:'\n}', 1:']', 2:''},
delimiter = {0: ',\n', 1:',\n', 2:','};
function closeLevel(level, noDelimiter) {
if(lastLevel === null)
return;
var l = lastLevel, d = level == lastLevel;
while(l >= level) {
result += close[l] + (l == level && !noDelimiter ? delimiter[l]:'');
l--;
}
}
this.level0 = function(arg) {
closeLevel(0);
result += arg + ' = {\n';
lastLevel = 0;
};
this.level1 = function(arg) {
closeLevel(1);
result += '\t' + arg + ': [';
lastLevel = 1;
};
this.level2 = function(arg) {
closeLevel(2);
result += arg;
lastLevel = 2;
};
this.getResult = function() {
closeLevel(lastLevel, true);
return result;
}
}
var p = new Printer();
p.level0('head');
p.level1('sub1');
p.level2('item1');p.level2('item2');p.level2('item3');
p.level1('sub2');
p.level1('sub3');
p.level2('newthing');
p.level0('head2');
document.getElementById('textarea').value = p.getResult();
You could see it in action here.
I'm not sure why you're building what looks like objects with nested arrays, using string concatenation. Something like this would be much simpler, since it wouldn't require fixing trailing commas, etc:
Edit: I've updated the code to make it keep track of the last level put in.
function Db() {
var level0, level1;
var data = new Object();
this.level0 = function(arg) {
level0 = new Object();
data[arg] = level0;
}
this.level1 = function(arg) {
level1 = new Array();
level0[arg] = level1;
}
this.level2 = function(arg) {
level1.push(arg);
}
this.toString = function() {
var s = '';
for(i in data) {
s += i + '\n';
for(j in data[i]) {
if(data[i][j].length>0) {
s += '\t' + j + ': [' + data[i][j] + ']\n' ;
}
}
}
return s;
}
}
Use like this:
var db = new Db();
db.level0('head');
db.level1('sub1');
db.level2('item1');db.level2('item2');db.level2('item3');
I've tested this in the demo you linked and it works just fine.

Categories