issue with array indexing - javascript

So I'll jump right to it...
I am a test automation engineer, and I am making a "keyword driven" testing system that is powered with JSON, which tie in with Selenium tests to run on a web browser.
The "keywords" are stored as XML files, and I have a JavaScript function which loads these keywords into an array, and also stores the Index of that keyword. to paf.keywordIndex
Example
$.get("getSteps.php", function(keywords) {
paf.keywords = eval(keywords); // stores into an array...
paf.keywordIndex = -1;
for ( var i = 0 ; i < paf.keywords.length ; i++ ) {
// for each path...
/* alert(paf.keywords[i]); */
$.ajax({url: "./_keywords/" + paf.keywords[i], success: function(xml) {
paf.xml = xml;
paf.keywordIndex++;
var title = $(xml).find("keyword").attr("title");
//var name = $(xml).find("keyword").attr("name");
paf.buffer += ("<option value=\"./_keywords/"+paf.keywords[paf.keywordIndex]+"\">"+title+"</option>");
},
async: false
//cache: false
});
}
$(stepSelectionLocator).html(paf.buffer);
});
getSteps.php is a php service that returns all the xml keywords in a json array. e.g.
["Login.xml","EndSession.xml", "SelectResult.xml", etc...]
Now this function works, but the only problem is, it's not sorted in ANY way. So the output would be -
Login (Login.xml)
Select a result (SelectResult.xml)
End a session (EndSession.xml)
To solve this issue, I added an extra attribute to my <keyword> so now it's <keyword area="basic"> to indicate that this is a basic step. and now my function is -
$.get("getSteps.php", function(keywords) {
paf.keywords = eval(keywords); // stores into an array...
paf.keywordIndex = -1;
for ( var i = 0 ; i < paf.keywords.length ; i++ ) {
// for each path...
/* alert(paf.keywords[i]); */
$.ajax({url: "./_keywords/" + paf.keywords[i], success: function(xml) {
paf.xml = xml;
paf.keywordIndex++;
var title = $(xml).find("keyword").attr("title");
var area = $(xml).find("keyword").attr("area");
//var name = $(xml).find("keyword").attr("name");
paf.buffer.push(area.toUpperCase() + ": " + title);
},
async: false
//cache: false
});
}
paf.buffer.sort(); // array is sorted...
paf.buffer2 = "";
paf.keywordIndex = -1;
for ( var a in paf.buffer ) {
paf.keywordIndex++;
paf.buffer2 += "<option value=\"./_keywords/"+paf.keywords[paf.keywordIndex]+"\">"+ paf.buffer[a] + "</option>";
}
$(stepSelectionLocator).html(paf.buffer2.toString().replace(",", ""));
});
Now the output is
BASIC: End the session (Login.xml)
BASIC: Login (SelectResult.xml)
RESULTS: Select a result (EndSession.xml)
So I've already determined that the index is the issue. However, I cannot figure out a way to fix this..
I am open to alternatives, so if you find a simpler way to index this, please let me know!

First of all, it'd be nice to know exactly the data you get from your initial request.
$.get("getSteps.php", function (keywords) {
paf.keywords = JSON.parse(keywords); // eval is bad! Use JSON.parse instead.
console.log(paf.keywords); // what does it output in the console?
...
Secondly, you can refer to the current index by using just the i variable. If you don't use paf.keywordIndex elsewhere, you can remove it because it's redundant.
Thirdly, are you absolutely, definitely, 100% sure that your ajax requests are *S*ynchronous? If they are not - the responses will arrive at random and the whole thing will require a different approach.
Finally, if you want to apply sorting to your keywords after you got them all, I would recommend pushing them into the buffer array as objects:
buffer.push({
keyword: keywordName, // this is the keyword name
keywordIndex: i, // this is the initial index
keywordArea: areaObtainedFromXML // this is the area you get from xml
});
By using the above approach you will be able to sort your buffer in many ways while retaining the initial order.
Please take a look at a contrived example at this jsfiddle.

Related

How to return a line from an array by searching for a specific value in said line

good evening, I am trying to use a single value to search an array, and return the full line the said value is in.
The Array is set up like this in string form:
Xanax,Brand,Anxiety,Code
However, now I'm stuck with calling back only the Medication, and not the full line the Medication is in, sadly. I would like to be able to grab each variable in a line, and make them their own independent variables outside of the array so I can use them for something else.
this.importDataObject("MEDDIAGNOSISICD-10.txt", "C:/Users/dell/Documents/tab
excel/MEDDIAGNOSISICD-10.txt");
var oFile = this.getDataObjectContents("MEDDIAGNOSISICD-10.txt");
var cFile = util.stringFromStream(oFile, "utf-8");
var fileArray = cFile.split('\t');
var Med = this.getField("Medications 1");
var Index = fileArray.indexOf(Med.value);
var Call = fileArray[Index];
console.println(Call);
Any help would be wonderful!
It's because you are running the indexOf method on the whole array, you need to run it on the each value instead. Try a for loop before you check IndexOf method.
Like this:
var i, Index;
for (i = 0; i < fileArray.length; i++) {
Index = fileArray[i].indexOf(Med.value);
if(Index > -1) console.log('Your search is found in ' + fileArray[i] );
}
Note that, in here the variable Index will be 0 or larger if that search is successful. And will be of value -1 if no match is found.

Recursive traversal of unknown json object/tree and actions based on returned json

I'm using a API that returns JSON on request. This JSON has either names for next level URL's or a filename.
The problem is that code has to recognize which JSON is returned.
If JSON only has a names for next url levels then create url and get it.
Then recursively get a new set of names or files, recognize and do it over. It can go as menu levels deep as required. 1 to *
If it has a filename it should get it and render it as html.
(This is already solved)
Example of json
{id: 'New_url_1_level_1', id:'New_url_2_level_1', id:'New_url_3_level_1'}
//or
{id:'001200.file.ext',id:'001300.file.ext'...}
These would turn into http://my.api.call.com/New_url_1_level_1.../New_url1_level_2/...
The problem is that how to loop over URL's and to finally get to filename for example:
http://my.api.call.com/New_url_1_level_1/New_url_1_level_2/New_url_1_level_3/001300.file.ext
My current script is:
var json;
var urllevel= '/First_level';
var api = 'http://my.api.call.com';
var re = /^\d+/g; // Regex to match filename (decide if json has filenames or urls; files always start with digits or end with extension)
var loopApiUrl = new Array();
var recursion = false;
// This is the problem - how to recursively build url's based on returned data i.e. traverse a "unknown" tree
function recursePxJson(){
if (!recursion) {
loopApiUrl = [];
}
// Get JSON
$.get(api+urllevel+'/'+loopApiUrl.join('/'),function(data,status){
for (var i in data) {
if (!re.test(data[i].id)) { // {id: 'This_is_to_be_appended_to_url', id:'Another_appendable'}
recursion = true;
loopApiUrl.push(data[i].id);
recursePxJson();
}
else { // {id:'001200.file.ext',id:'001300.file.ext'}
load(api+urllevel+'/'+loopApiUrl.join('/')+'/'+data[i].id);
recursion = false;
}
}
});
//loadDBS(param);
}
// Load renderable JSON - ALREADY SOLVED
function load(param){
$.get(param, function(data, status){
json = JSON.stringify(data);
var title = data.title.split(':');
html = '<h2>'+title[0]+'</h2>';
html += '<h3>'+title[1]+'</h3>';
html += '<h5>Values:</h5>';
for (var i=0; i<data.variables.length; i++) {
html += '<b>'+data.variables[i].text+': </b>';
varlen = data.variables[i].valueTexts.length;
if (varlen > 6) {
html += '<i>'+data.variables[i].valueTexts[0]+', '+data.variables[i].valueTexts[1]+', '+data.variables[i].valueTexts[2]+' . . . '+data.variables[i].valueTexts[varlen-3]+', '+data.variables[i].valueTexts[varlen-2]+', '+data.variables[i].valueTexts[varlen-1]+'</i>'+'<b> (yhteensä '+varlen+' arvoa)</b>';
} else {
html += '<i>'+data.variables[i].valueTexts.join(',')+'</i>';
}
html += '<br/>';
}
$(html+'<br>').appendTo($('#tab2'));
});
}
EDIT: At the moment it seems like it is does each for loop before it begins another. Therefore it starts one in loop and if another is instatiated it won't be run before the fist one is done.
Main loop
Internal Loop 1
Internal Loop 2 <- Isn't this the one that should done first?
Handle your loopApiUrl variable as a parameter for your function recursePxJson().
Get rid of the useless recursion boolean.
You may find it easier to ditch jQuery and make use of a plain old XMLHTTPRequest. Your code will be slightly longer but you'll gain a better control of what your doing.

Is it possible to use a string to reference a json object within an Ajax statement?

So i have a javascript function. It performs one ajax call, to retrieve a json object full of data. Within the success function of that ajax call i perfrom ANOTHER ajax call to retrieve the names of the columns of data for that particular set. (yes i'm sure there's a better way but thats not my issue). At this point in time i have two variables: items(json array) and interfaceCols(just an array of strings). Then i try to create an html string to create a table with said data.
Here is my code which will make everything more clear:
$.ajax({
url:"/ryan/nonEmber/ajax.php?table=Interfaces",
beforeSend: function(XMLHttpRequest){},
success: function(data, textStatus) {
interfaceCols = data.split(" ");
$.getJSON("/ryan/nonEmber/getJson.php?table=Interfaces", function( data ){
var items = [];
$.each(data.post, function(key, val){
items.push(val);
});
for(i = 0; i < items.length; i++){
var myString = '<tr id = "visibleRow">';
console.log(items[i].interfaceCols[4]);
for(j = 0; j < interfaceCols.length; j++){
myString = myString + '<td id = "visibleDef">' + items[i].interfaceCols[j] +'</td>';
}
myString = myString + '</tr>';
interfaces.push(myString);
}
});
}
});
My javascript file throws an error on the "myString = myString + '<td id ='... line.
I am almost positive that it is because i'm just placing a string at the end of "items[i]" with ".interfaceCols[j]"
Can anybody suggest a way to do this? The whole point is so that i dont have to manually type out every column name, because i have alot of tables and each table has many columns.
Given a JS object s:
s = {a: 1, b: 2}
You have (at least) two options to access an attribute:
s.a // returns 1
Which seems to be what you are trying to do right now. To access it with a dynamic name, you can use:
s['a'] // returns 1
In your case, it should be:
items[i][interfaceCols[4]]

Page with multiple dropdown filters

I have a page which uses dropdowns to filter a listing. I have over 10 filters now and each of the change function, I am calling an AJAX request and passing corresponding variables to the PHP function. Like this :
$("#categories").change(function() {
uri = "myurl" ;
var status=$("#statusfilter").val();
var category=$("#categories").val();
var network=$("#networksfilter").val();
var prod_type = $("#prodtypefilter").val();
loadData(uri,category,status,network,prod_type);
});
and in loadData() I have the following code :
function loadData(uri,category,status,network,prod_type){
url + = category+"/"+status+"/"+network+"/"+prod_type;
$('#userdata').load(url);
}
Here I have given only 4 filters only, but it is actually 10 and may increase.Anyway this is working fine. But the problem is that as I increase the filters, I need to write this same for every dropdown change function. Is there any better approach to optimze the code and so I don't need to load a bunch of JS ?
Rename your filter elements' IDs to start with same word, for example "filter_". Then get all of them at once:
$('select[id^="filter_"]').change(function() {
var uri = "myurl";
var filters = new Array();
$('select[id^="filter_"]').map(function () {
filters[$(this).name()] = $(this).val(); // not tested, just an idea
});
loadData(uri,filters);
});
.map() iterates over its elements, invoking a function on each of them and recording the selected option value in the array.
You can use .each() if it's more intuitive from .map() for you:
$.each('select[id^="filter_"]', function() {
filters[$(this).name()] = $(this).val(); // not tested, just an idea
});
Note: It's a good idea to use associative array as #Tony noticed below to be sure which filter is for which database table attribute in your server side script.
You will need to write some code in any cases, but you can reduce it, for example like this:
$("#categories").change(function() {
uri = "myurl";
var filters = {
status: $("#statusfilter").val(),
category: $("#categories").val(),
network: $("#networksfilter").val(),
prod_type: $("#prodtypefilter").val()
}; // order is important
loadData(filters );
});
loadData(filters) {
var url = '';
for (var filterName in filters)
url += '/' + (filters[filterName] || 'any'); // here some def value needed
url = url.substring(1); // cut first slash
$('#userdata').load(url);
}
EDIT
Or even like this:
loadData(filters) {
var url = Object.keys(filters).map(function(el) {
return filters[el] || 'any';
}).join('/');
$('#userdata').load(url);
}

Dictionary in JavaScript

Currently I tried to reform my JSON data to a dictionary to store only needed data in an array with key and value.
* Edit to put my full code. *
This is how I do:
var myData = [];
var urlPath = "https://tipjira.pgdev.abcd.com/rest/api/2/search?jql=project=GRIFR14%2Band%2BfixVersion=15018";
var jiraMapping = [];
$.ajax({
url : "http://frparwself22.dhcp.par.abcd.com:8080/jiraproxy/jira?url=" + urlPath,
dataType : 'json',
type: 'GET',
success : function(data) {
for (var i=0; i<data.issues.length; i++) {
var obj = {};
obj[data.issues[i].key] = data.issues[i].self;
jiraMapping.push(obj);
alert(jiraMapping.length);
}
},
error : function() {
alert("Error!")
}
});
alert(jiraMapping.length);
My original data is {issues:[{...,"self":"/rest/api/2/issue/175074","key":"GRIFR14-36",...}, {...,"self":"/rest/api/2/issue/175075","key":"GRIFR14-37",...}, ...]}. And I want to reform to have the array with key and value which are key and self.
So the data in my jiraMapping should be something like [{k1:v1}, {k2,v2}, ...].
But when I tired to print the length of jiraMapping, the length is 0.
I tried to put alert to check key and value that I add to the array and the values exist.
I don't know where is the problem exactly. Please help...
Without knowing exactly what information you're passing in, it's hard to say what's going wrong. That being said, my first guess is that data/myData isn't formatted the way you think. For instance, if myData.issues.length is 0, nothing in the loop will get executed.
There's also a chance that you're never actually running the success function. Could you post some more code?
The problem lies in the data that you are receiving or you have a typo somewhere later when checking length. This all looks fine, and I tried to replicate your problem like this:
var jiraMapping = [];
var myData = [{"A":"a"},{"B":"b"}];
for (var i=0; i<myData.length; i++) {
var obj = {};
obj[myData[i]] = myData[i];
jiraMapping.push(obj);
}
console.log(jiraMapping);
but this works fine, fiddle here: http://jsfiddle.net/GWpBs/2/

Categories