Why is a named function not working when the unnamed was? - javascript
I had this code:
$('#testsPane').live("click", function() {//if the secondary ui nav tests is
selected
//Displays the test list
var listOfTests = "";
var subjects = [];
var tests= [];
var titles = [];
var keysplit;
var testSubj;
var key, value;
for (var i = 0; i < localStorage.length; i++) {
key = localStorage.key(i);
value = localStorage.getItem(key);
keysplit = key.split(".");
tests.push(value);
titles.push(keysplit[0]);
subjects.push(keysplit[keysplit.length-1]);
}
for(var i=0; i < tests.length; i++) {
listOfTests += '<div class="testDisplayBox"><div
class="subjColorBar"></div><div class="testListIndiContain"><span
class="testListTitle">' + titles[titles.length-(i+1)] + '</span><span> in
</span><span class="testListSubj">' + subjects[subjects.length-(i+1)] +
'</span></div><div class="testListTags"><span
class="specTags">quiz</span></div></div>';
}
var testsDashboard = '<div id="testsList">' + listOfTests + '</div>';
$('#selectedPane').append(testsDashboard);//adds the html to the pane to make it
into the tests dashboard
})
The above code worked but I wanted to reuse some of it so I put it into a function. When I did that it did not work. Any idea why? The code below is with using a named function.
function grabTestList() {//Displays the test list
var keysplit;
var testSubj;
var key, value;
for (var i = 0; i < localStorage.length; i++) {
key = localStorage.key(i);
value = localStorage.getItem(key);
keysplit = key.split(".");
tests.push(value);
titles.push(keysplit[0]);
subjects.push(keysplit[keysplit.length-1]);
}}
$('#testsPane').live("click", function() {//if the secondary ui nav tests is selected
grabTestList();
var listOfTests = "";
var subjects = [];
var tests= [];
var titles = [];
for(var i=0; i < tests.length; i++) {
listOfTests += '<div class="testDisplayBox"><div class="subjColorBar"></div><div class="testListIndiContain"><span class="testListTitle">' + titles[titles.length-
(i+1)] + '</span><span> in </span><span class="testListSubj">' + subjects[subjects.length-(i+1)] + '</span></div><div class="testListTags"><span
class="specTags">quiz</span></div></div>';
}
var testsDashboard = '<div id="testsList">' + listOfTests + '</div>';
$('#selectedPane').append(testsDashboard);//adds the html to the pane to make it into the tests dashboard
})
Because you are defining variables in the context of the anonymous function which are unknown to the named function. Pass them to grabTestList so the .push methods can mutate those arrays.
function grabTestList(tests, titles, subjects) {
// manipulate tests/titles/subjects
}
$('blah').live('click', function() {
var tests = [], titles = [], subjects = [];
grabTestList( tests, titles, subjects );
// since tests, titles, and subjects are mutated by the function, you can just loop through them here.
})
DEMO:
Here's a sample version which you can base your code on: http://jsfiddle.net/JLK6N/2/
updated with the fix: http://jsfiddle.net/JLK6N/3/
Remember that objects are passed by reference, arrays are objects, and methods like .push are mutator methods.
Related
Nested loop only rendering last indexed item using jquery appendPe
Performing an ajax call to a drinks api and I've nested a loop to pull the ingredients out and render them to the page. The nested loop consoles the ingredients correctly but when I use jquery to append the results to the page only the item in the last index is displayed. I know there are null values I was going to remove them with an if statement after I got them to show. function displayDrinkData(drinkName) { var queryURL = "https://thecocktaildb.com/api/json/v1/1/search.php?s=" + drinkName $.ajax({ url: queryURL, method: "GET" }).then(function (response) { console.log(response); var results = response.drinks; for (var i = 0; i < results.length; i++) { console.log(results[i]); var eachDrink = results[i]; var drinkDiv = $("<div>"); var drinkName = results[i].strDrink; for (var k = 1; k < 16; k++) { console.log(eachDrink['strIngredient' + k]); var ingList = $("<ul>").text("Ingredients: " + eachDrink['strIngredient' + k]) } var pOne = $("<p>").text("Drink name: " + drinkName); var drinkInstructions = results[i].strInstructions; var pTwo = $("<p>").text("Instructions: " + drinkInstructions); var drinkImage = $("<img>"); drinkImage.attr("src", results[i].strDrinkThumb); drinkDiv.append(pOne); drinkDiv.append(ingList); drinkDiv.append(pTwo); drinkDiv.append(drinkImage); $("#drinks-view").append(drinkDiv); } }) }
Because var ingList is inside loop, not appending, but creating a new one every time. var ingList = $("<ul>"); for (var k = 1; k < 16; k++) { console.log(eachDrink['strIngredient' + k]); ingList.append($('<li>').text("Ingredients: " + eachDrink['strIngredient' + k])); } Declare variable outside loop, and append <li> for each element.
Spliting String and getting appropriate value in JavaScript
I have a string where |||| means next to it is the directory. ||| means the user is allowed to access this directory and || means the files allocated to these users follow. I need to find allocated file names of a specific user from this string. I have tried to split the string and assign values to an array but I am not able to get the result I'm looking for. This is the string: ||||Root|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,||||1400842226669|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,||||1401191909489|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,LimitTest_20140528164643.xlsx, And here is my attempt: function getData() { var user = 'km11285c'; var value = "||||Root|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,||||1400842226669|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,||||1401191909489|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,LimitTest_20140528164643.xlsx,"; var users = null; var files = null; var Dir = value.split("||||"); var arrayLength = Dir.length; for (var i = 0; i < arrayLength; i++) { users = Dir[i].split("|||"); } return users; } console.log(getData()); and the jsFiddle
I changed your jsfiddle example a bit so maybe you need to change the code here and there, but something like this should work: function buildTree(data) { var tree = []; var dirs = data.split("||||"); // Remove the first entry in the array, since it should be empty. dirs.splice(0, 1); for (var i = 0; i < dirs.length; ++i) { var tempArray = dirs[i].split("|||"); var dirName = tempArray[0]; var usersAndFiles = tempArray[1]; tempArray = usersAndFiles.split("||"); var users = tempArray[0]; var files = tempArray[1]; var treeDir = { name: dirName }; treeDir.users = users.split(","); treeDir.files = files.split(","); tree.push(treeDir); } return tree; } function getData() { var user = 'km11285c'; var value="||||Root|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,||||1400842226669|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,||||1401191909489|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,LimitTest_20140528164643.xlsx,"; var tree = buildTree(value); for (var i = 0; i < tree.length; ++i) { var dir = tree[i]; if (dir.users.indexOf(user) >= 0) { console.log("User '" + user + "' has access to directory '" + dir.name + "', which contains these files: " + dir.files.join(",")); } } } getData();
generate list of variables from a FOR loop
var select = []; for (var i = 0; i < nameslots; i += 1) { select[i] = this.value; } This is an extract of my code. I want to generate a list of variables (select1, select2, etc. depending on the length of nameslots in the for. This doesn't seem to be working. How can I achieve this? If you require the full code I can post it. EDIT: full code for this specific function. //name and time slots function gennametime() { document.getElementById('slots').innerHTML = ''; var namelist = editnamebox.children, slotnameHtml = '', optionlist; nameslots = document.getElementById('setpresentslots').value; for (var f = 0; f < namelist.length; f += 1) { slotnameHtml += '<option>' + namelist[f].children[0].value + '</option>'; }; var select = []; for (var i = 0; i < nameslots; i += 1) { var slotname = document.createElement('select'), slottime = document.createElement('select'), slotlist = document.createElement('li'); slotname.id = 'personname' + i; slottime.id = 'persontime' + i; slottime.className = 'persontime'; slotname.innerHTML = slotnameHtml; slottime.innerHTML = '<optgroup><option value="1">00:01</option><option value="2">00:02</option><option value="3">00:03</option><option value="4">00:04</option><option value="5">00:05</option><option value="6">00:06</option><option value="7">00:07</option><option value="8">00:08</option><option value="9">00:09</option><option value="10">00:10</option><option value="15">00:15</option><option value="20">00:20</option><option value="25">00:25</option><option value="30">00:30</option><option value="35">00:35</option><option value="40">00:40</option><option value="45">00:45</option><option value="50">00:50</option><option value="55">00:55</option><option value="60">1:00</option><option value="75">1:15</option><option value="90">1:30</option><option value="105">1:45</option><option value="120">2:00</option></optgroup>'; slotlist.appendChild(slotname); slotlist.appendChild(slottime); document.getElementById('slots').appendChild(slotlist); (function (slottime) { slottime.addEventListener("change", function () { select[i] = this.value; }); })(slottime); } }
You'll have to close in the iterator as well in that IIFE (function (slottime, j) { slottime.addEventListener("change", function () { select[j] = this.value; }); })(slottime, i); and it's only updated when the element actually change
The cool thing about JavaScript arrays is that you can add things to them after the fact. var select = []; for(var i = 0; i < nameSlots; i++) { var newValue = this.value; // Push appends the new value to the end of the array. select.push(newValue); }
How to add dynamically HTML element using JavaScript and Firefox Add-on SDK
I am developing a simple add-on with Firefox SDK that allows the user to review the stored data. I would like to show the items in a panel with a table. The table is created dynamically with the data incoming from the data-base. Firstly, In the JavaScript code I create the items with their properties, then I create a table with the properties as row and I append the items with the value of each properties. I have some problems: the table has only the item's name as first row and the properties name as first column without the value in the cells. It seems that the code is not executed in order, but it seems that the faster functions are executed first. This is the code: self.on('message', function() { var container = $('#container'); container.empty(); items = []; self.port.emit('getItem'); }); self.port.on('items', function(response) { var ok = 0; var items = []; var table = $('#tableContainer #table').clone(); var container = $('#container'); table.append("<tr id=first><th> </th></tr>"); var json = eval('('+ response + ')'); for (var i = 0, len = json.length; i < len; ++i) { var item = { id: json[i], properties: [] }; items.push(item); } items.forEach ( function(item) { table.find('#first').append("<th id="+item.id+">"+item.id+"</th>"); self.port.emit('detailsItem', item.id); self.port.on('details'+item.id, function(response) { var details = eval('('+ response + ')'); var description = []; ndet = details.length; var len = details.length; for (var i = 0; i < len;) { var detail = { dimension : details[i].dimension, value : details[i].value } description.push(detail); ++i; } item.properties = description; }); }); self.port.emit('getDimension'); self.port.on('dimension', function(response) { var dimensions = eval('('+ response + ')'); for(var cont = 0, l = dimensions.length; cont < l; ++cont) { table.append("<tr id=dimension"+cont+"><td>"+dimensions[cont]+"</td></tr>"); items.forEach( function(item) { var prop = []; prop = item.properties; var lun = prop.length; for( var p =0;p < lun;) { if(item.properties[p].dimension == dimensions[cont]) { table.find('#dimension'+cont).append("<td>"+item.properties[p].value+"</td>"); } else { table.find('#dimension'+cont).append("<td> --- </td>"); } ++p; } }); }; }); container.append(table); });
javascript, .split(), implement additional variable
I found a code for city,state dropdown menu. It works flawlessly, but I am implementing additional feature by adding a US State to the following code: //countries array var countries = Object(); countries['Africa'] = '|Algeria|Angola|Benin'; //state array var city_states = Object(); city_states['United States'] = '|Washington DC||Alabama|Alaska'; this is an array for US Cities, but I want to add a State abbreviation like so: DC, AL, AK and so on to be sent to the menu such as this: function setRegions() { for (region in countries) document.write('<option value="' + region + '">' + region + '</option>'); } function set_country(oRegionSel, oCountrySel, oCity_StateSel) { var countryArr; oCountrySel.length = 0; oCity_StateSel.length = 0; var region = oRegionSel.options[oRegionSel.selectedIndex].text; if (countries[region]) { oCountrySel.disabled = false; oCity_StateSel.disabled = true; oCountrySel.options[0] = new Option('SELECT COUNTRY',''); countryArr = countries[region].split('|'); for (var i = 0; i < countryArr.length; i++) oCountrySel.options[i + 1] = new Option(countryArr[i], countryArr[i]); document.getElementById('txtregion').innerHTML = region; document.getElementById('txtplacename').innerHTML = ''; } else oCountrySel.disabled = true; } function set_city_state(oCountrySel, oCity_StateSel) { var city_stateArr; oCity_StateSel.length = 0; var country = oCountrySel.options[oCountrySel.selectedIndex].text; if (city_states[country]) { oCity_StateSel.disabled = false; oCity_StateSel.options[0] = new Option('SELECT NEAREST DIVISION',''); city_stateArr = city_states[country].split('|'); for (var i = 0; i < city_stateArr.length; i++) oCity_StateSel.options[i+1] = new Option(city_stateArr[i],city_stateArr[i]); document.getElementById('txtplacename').innerHTML = country; } else oCity_StateSel.disabled = true; } function print_city_state(oCountrySel, oCity_StateSel) { var country = oCountrySel.options[oCountrySel.selectedIndex].text; var city_state = oCity_StateSel.options[oCity_StateSel.selectedIndex].text; if (city_state && city_states[country].indexOf(city_state) != -1) document.getElementById('txtplacename').innerHTML = city_state + ', ' + country; else document.getElementById('txtplacename').innerHTML = country; } I was thinking adding an additional array of State abbreviations, but I think adding a simple state abbreviation to the already built array would do just fine by adding another value in the setregions() and having + abbreviation + instead of + region +. Any ideas how to implement it? -thank you.
If you have an array of States (objects) rather than an array of Strings you could do something like this: function State(longName, shortName) { this.longName = longName; this.shortName = shortName; } I don't know what the abbreviations are, but store them like this in your array var cityStates = "State:Abbrev|Washington DC:WDC|ETC:etc" var stateNames = cityStates.split("|"); var states = new Array(stateNames.length); for (i=0; i<states.length; i++) var longName = stateNames[i].split(":")[0]; var shortName = stateNames[i].split(":")[1]; states[i] = new State(longName,shortName); } That would give you a new array "states" with 50 state objects, each which could be called like this: states[0] //(returns a State object at index 0) states[0].longName //(returns the long name) states[0].shortName //(returns the abbreviated name)