Number expected error on sort - javascript

Other browsers work fine but in IE i get Number Expected when using the following code and it runs into a null object on the sort function.
http://jsfiddle.net/R3ndd/2/
function list_response(jsonData) {
"use strict";
var lists = document.getElementById("lists"), anchors = document.getElementById("anchors"), jItems = jsonData.items;
var results = [], anks = [], vList, pListName, item, videoItem;
var i, j, jLen, iLen = jItems.length;
for (var i = 0; i < iLen; i++) {
if(jItems[i] != null ){
jItems[i].nameLower = jItems[i].name.toLowerCase();
}
}
jItems.sort(function (a, b) {
if(a != null && b != null){
return a.nameLower.localeCompare(b.nameLower);
}
});
Any suggestions? Thanks!
My Solution
I decided to remove the null object (which works) from json using the following:
var y;
for (var x in jItems) {
if ( Object.prototype.hasOwnProperty.call(jItems,x)) {
y = jItems[x];
if (y==="null" || y===null || y==="" || typeof y === "undefined") {
delete jItems[x];
}
}
}

Don't know why IE does that, but it is it's habit to trouble us good people :). Well, I think this will be better way.
/* NOT NEEDED.
for (var i = 0; i < iLen; i++) {
if(jItems[i] != null ){
jItems[i].nameLower = jItems[i].name.toLowerCase();
}
}*/
jItems.sort(function (a, b) {
return a && b ? a.toLowerCase().localeCompare(b.toLowerCase()) : 0;
});
UPDATE:
Well, I think I know where IE is troubling. Sorry MS, this time IE hasn't any fault. What happened was that in case where either a or b were null/''/false (or any falsy value), your callback didn't return any value. That explians the 'Number expected' error. But I took care of that, so my answer will probably work. :)

Related

Find how many times "Index" appers in array

I'm trying to find out if "Index" exist in my array, and second then count how many time it does appear.
Nothing of what I'm trying is working, this is the best attempt i've made, but cant turn my head around this.
var arr = {"__metadata":{"id":"a5e55ca2-c574-434e-8ec3-1b9cd4595bcb","uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)","etag":"\"2\"","type":"SP.Data.SalesListItem"},"FirstUniqueAncestorSecurableObject":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/FirstUniqueAncestorSecurableObject"}},"RoleAssignments":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/RoleAssignments"}},"Activities":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/Activities"}},"AttachmentFiles":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/AttachmentFiles"}},"ContentType":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/ContentType"}},"GetDlpPolicyTip":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/GetDlpPolicyTip"}},"FieldValuesAsHtml":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/FieldValuesAsHtml"}},"FieldValuesAsText":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/FieldValuesAsText"}},"FieldValuesForEdit":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/FieldValuesForEdit"}},"File":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/File"}},"Folder":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/Folder"}},"ParentList":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/ParentList"}},"Properties":{"__deferred":{"uri":"https://lavanet.sharepoint.com/sites/devcla/_api/Web/Lists(guid'cc4de542-1c06-4f53-b787-b8a2d42fe21e')/Items(1)/Properties"}},"FileSystemObjectType":0,"Id":1,"ServerRedirectedEmbedUri":null,"ServerRedirectedEmbedUrl":"","ContentTypeId":"0x010048CF0CAB992F7B409B79C034586FFB7E","Title":"Test data 1","Date":"2017-01-01T08:00:00Z","Index":20,"Index2":15,"ID":1,"Modified":"2017-04-18T12:27:19Z","Created":"2017-02-03T10:02:10Z","AuthorId":17,"EditorId":17,"OData__UIVersionString":"1.0","Attachments":false,"GUID":"d87fa9d2-c81e-4dfd-b568-c8a300fc12d8"}
function containsObject(obj, list) {
var x;
for (x in list) {
if (list.hasOwnProperty(x) && list[x] === obj) {
return true;
}
}
return false;
}
console.log(containsObject("index", arr));
Would love if someone could help a bit
If you would like to count both if key and/or value of prop === index and not bother of case-sensitivity, then you can try something like this.
function containsObject(obj, list) {
var cnt = 0;
for (var x in list) {
var val = list.hasOwnProperty(x) && list[x] ? list[x].toString() : '';
if (x.toLowerCase() === obj.toLowerCase() ||
val.toLowerCase() === obj.toLowerCase()) {
cnt++;
}
}
return cnt;
}

Understanding this Javascript function

I am continuing a project. And this is the only thing I do not understand. It is the key function for assembling a filter string to be used for sql query. This function is invoke via onclick of a button.
My problem is the value for query is taken from $_REQUEST['FILTER'].
<input id="HDN_FILTER" name="FILTER" type="hidden" value="<?php echo $_REQUEST['FILTER']; ?>">
At first $_REQUEST['FILTER'] is empty. Then upon pressing the submit button it assembles and return the string. But I don't understand how it assembled the string. Because it seems the function get its value from this input. But it's value is empty. So the function should received empty from this input. It's like going in circles
Example what does "" != means in javascipt anyway?
An example of the assembled string is ""DELIVER_STORE_ACCOUNT=ALL^STORES_ACCOUNT=ALL^ACTIVE=1^PART_NUMBER=ALL^NEW_PART_NUMBER=ALL""
And I see the join("^") part in the function. And it seems this line assembles it. But why is it inside a switch parenthesis?
function SUBMIT(e, t) {
array_Filter = new Array;
for (i in array_Dropdown) {
if (varField = array_Dropdown[i], varID = "SEL_" + varField, aryTemp = new Array, -1 != document.getElementById(varID).selectedIndex)
for (i = 0; i < document.getElementById(varID).options.length; i++)
document.getElementById(varID).options[i].selected === !0 && (aryTemp[aryTemp.length] = document.getElementById(varID).options[i].value);
aryTemp.length > 0 && (array_Filter[varField] = aryTemp)
}
"" != document.getElementById("HDN_SEARCH").value && (aryTemp.SEARCH = document.getElementById("HDN_SEARCH").value), array_Filter_Temp = new Array;
for (i in array_Filter)
array_Filter_Temp[array_Filter_Temp.length] = i + "=" + array_Filter[i].join("|");
switch (varFilter = array_Filter_Temp.join("^"), document.getElementById("HDN_FILTER").value = varFilter, document.getElementById("HDN_EXCEL").value = 1 == e ? 1 : 0, !0) {
case 1 == t:
document.getElementById("HDN_OVERRIDE").value = 1;
break;
case 0 == t:
document.getElementById("HDN_OVERRIDE").value = 0;
break;
case-1 == t:
}
varTXTBOX = document.getElementById("TXT_SEARCH").value;
alert(varTXTBOX);
document.getElementById("FORM1").submit()
}
Whoever wrote this code was trying to obfuscate it, making it hard for anyone else to understand what it does, perhaps because the result is sent to a SQL query, as you stated. Of course, if you want to hide anything from your users, specially SQL commands, implement it server-side.
1) The "" != part:
"" != document.getElementById("HDN_SEARCH").value // left side
&& // logical AND
(aryTemp.SEARCH = document.getElementById("HDN_SEARCH").value), // right side
array_Filter_Temp = new Array; // another statement
Here he's taking advantage of the short-circuit evaluation, if the left side of the expression evaluates to false, then the right side isn't executed. The next statement after the , is always executed (read more about the comma operator). So it's the same as writing:
if (document.getElementById("HDN_SEARCH").value != "") {
aryTemp.SEARCH = document.getElementById("HDN_SEARCH").value
}
array_Filter_Temp = new Array;
2) The switch part:
switch (
varFilter = array_Filter_Temp.join("^"),
document.getElementById("HDN_FILTER").value = varFilter,
document.getElementById("HDN_EXCEL").value = 1 == e ? 1 : 0,
!0
) {
The first two are trivial. On the third one, he is assigning HDN_EXCEL based on the value of e. Adding parenthesis makes it clearer: document.getElementById("HDN_EXCEL").value = (1 == e) ? 1 : 0
The !0 is there just to make sure the rest of the switch is executed (it evaluates to true). If it was 0 or false, then HDN_OVERRIDE would never be assigned to a value.
So that whole set could be rewritten as:
varFilter = array_Filter_Temp.join("^");
document.getElementById("HDN_FILTER").value = varFilter;
document.getElementById("HDN_EXCEL").value = (e == 1) ? 1 : 0;
switch (t) {
case 1:
document.getElementById("HDN_OVERRIDE").value = 1;
break;
case 0:
document.getElementById("HDN_OVERRIDE").value = 0;
break;
}
3) The first for loop: (you haven't asked, but here it goes anyway)
for (i in array_Dropdown) {
if (
varField = array_Dropdown[i],
varID = "SEL_" + varField,
aryTemp = new Array,
-1 != document.getElementById(varID).selectedIndex
)
for (i = 0; i < document.getElementById(varID).options.length; i++)
document.getElementById(varID).options[i].selected === !0 && (aryTemp[aryTemp.length] = document.getElementById(varID).options[i].value);
aryTemp.length > 0 && (array_Filter[varField] = aryTemp)
}
Again the use of the , operator to execute all commands and return the value of the last one to the if, which is -1 != document.getElementById(varID).selectedIndex, so the second for loop will run only if the element in varID has a selectedIndex.
The === !0 is the same as === true.
This could be rewritten as:
for (key in array_Dropdown) {
varField = array_Dropdown[key];
varID = "SEL_" + varField;
aryTemp = new Array;
if (document.getElementById(varID).selectedIndex != -1) {
for (i = 0; i < document.getElementById(varID).options.length; i++) {
if (document.getElementById(varID).options[i].selected) {
aryTemp[aryTemp.length] = document.getElementById(varID).options[i].value;
}
}
}
if (aryTemp.length > 0) {
array_Filter[varField] = aryTemp;
}
}
As a side note, if you can, I suggest you refactor this code, send only the collected data to the server and do all the transformation needed on the server-side.

Javascript TypeError: Array is undefined

to test some things in javascript I am building a small minesweeper.
The following code is the initialization of the two-dimension array P.field. Afterwards a number of random fields are getting filled with an x, symbolizing that there's a mine on this field.
P.field = new Array(num);
for (var i = 0; i < P.field.length; i++)
P.field[i] = new Array(num);
$.each(P.field, function(index, key) {
$.each(key, function(i, k) {
P.field[index][i] = '-';
});
});
var arr = [];
while (arr.length < 10) {
var found = false;
var randomnumber = Math.ceil(Math.random()*(num*num-1));
for (var i = 0; i < arr.length; i++)
if (arr[i] == randomnumber) { found = true; break; }
if (!found) arr[arr.length] = randomnumber;
}
for (var i = 0; i < arr.length; i++) {
P.field[ Math.floor(arr[i]/num) ][ Math.floor(arr[i]-Math.floor(arr[i]/num)*num)-1 ] = 'x';
}
However, in my algorithm for counting the mines in surrounding fields, I get the console error TypeError: P.field[(r+1)] is undefined. Every field (except of those from the last row) returns this error, which is something I can't quite understand.
P.field[rows][columns] has a length of 10 per dimension in my tests ([10][10]). When I try to get the value of P.field[9][0] to P.field[9][9] there's nothing wrong. However when I adress any smaller row, this exception kicks in (P.field[0 + 1][0], P.field[3 + 1][6], and what so ever)...
I hope someone can tell me why.
edit
More code:
onReady: function() {
$('#sweeper table').on('click', 'td', function(e) {
var row = $(this).parent().attr('class'); // Class represents the index of the array
var column = $(this).attr('class'); // Class represents the index of the array
P.openField(row, column, $(this));
});
},
openField: function(r, c, e) {
if ( P.field[r][c] == 'x' ) {
e.addClass('mine');
} else {
e.html( P.surroundingMineCount(r, c) );
e.addClass('opened');
}
},
surroundingMineCount: function(r, c) {
var count = 0;
if ( P.field[r][c-1] == 'x' ) count++;
if ( P.field[r-1][c-1] == 'x' ) count++;
if ( P.field[r][c+1] == 'x' ) count++;
if ( P.field[r-1][c] == 'x' ) count++;
if ( P.field[r-1][c+1] == 'x' ) count++;
if ( P.field[r+1][c] == 'x' ) count++;
if ( P.field[r+1][c-1] == 'x' ) count++;
return count;
},
Right now I have no validation if the r+1 or r-1 is actually a valid index for that array (I had one in, but removed it for testing). However that can't really be the error, because I even get errors in the middle of the table.
Looking at the code you've provided versus the errors you've had thrown, I'm skeptical about your suspected cause as the code used does indeed generate the correct set of arrays.
I suspect it may be a slightly simpler issue, the example generation code you've provided uses:
P.field = new Array(num);
which has P as a capital, whereas the error that you've had thrown uses it as lowercase:
TypeError: p.field[(r+1)] is undefined
Are you sure you haven't accidentally just used the incorrect case when testing?

How to check for specific string in a dictionary?

I have a dictionary like:
a = {"staticData":['----','Blue','Green'], "inData":['Indatahere','----','----']}
How can I find that if the dictionary contains "----", in any of the key's values.
Any Javascript function?
EDIT:
What if the case is like this?
a = {"staticData":[], "inData":['Indatahere','----','----']}
It's giving this Error:
TypeError: a[elem].indexOf is not a function
Here is the code:
var a = {"staticData":['----','Blue','Green'], "inData":['Indatahere','----','----']};
for(var key in a){
var value = a[key];
for(var i=0; i<value.length; i++){
if(value[i] == '----') alert("Found '----' in '" + key + "' at index " + i);
};
}
EDIT: Changed iteration over array to normal way after comment.
Use indexOf to search each array in the a object:
for (elem in a)
{
if (a[elem].indexOf("----") != -1)
alert('---- found at ' + a[elem]);
}
EDIT
For this error: TypeError: a[elem].indexOf is not a function the browser possibly considers an empty element to be a non-string type; non-string type does not have an indexOf method.
This code checks the length of the array element (if the element is empty before interpreting the indexOf function.
for (elem in a)
{
if (a[elem].length > 0 && a[elem].indexOf("----") != -1)
alert('---- found at ' + a[elem]);
}
If you wish to support IE < 9, see this post to conditionally add a indexOf definition to the Array object. The post also mentions a Jquery alternative.
The SO post mentioned above lists this Mozilla version of indexOf function.
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
If you know exactly the nesting level of your value, then a quick solution (as suggested in other answers) is possible.
However, if you need a deep traversal search, you're gonna need a recursive version of the solutions, something like:
function FindTraverse(data, match)
{
for (var prop in data)
{
if (!data.hasOwnProperty(prop)) continue;
if (data[prop] == match) return true;
if (typeof data[prop] == 'object' && FindTraverse(data[prop], match)) return true;
}
return false;
}
Examples:
FindTraverse({a:'Foo',b:'Bar'}, 'Bar') // true
FindTraverse(['Foo','Bar'], 'Bar') // true
FindTraverse([{name:'Foo'},{name:'Bar'}], 'Bar') // true
FindTraverse({a:{name:'FooBar'},b:'Bar'}, 'FooBar') // true
However, if you're looking for a more thorough solution, use a framework like jsTraverse
Use Object.getOwnPropertyNames().
You have to write two nested loops. With Object.getOwnPropertyNames you are accessing an array which consists of property names of an object. You will then need to loop over the value of those properties and identify the correct element within this second array.
a = {"staticData":['----','Blue','Green'], "inData":['Indatahere','----','----']}
props = Object.getOwnPropertyNames(a);
for (i=0;i < props.length;i ++) {
for (z = 0; z < a[props[i]].length; z ++) {
//console.log(a[props[i]][z])
if ( (a[props[i]][z]) == '----') {
console.log("I have found an item with ----")
};
}
}

Javascript Function to split and return a value from a string

I am trying to grab a certain value. I am new to javascript and I can't figure out why this is not working.
If I parse "kid_2" I should get "kostas". Instead of "Kostas" I always get "02-23-2000". So I must have a logic problem in the loop but I am really stuck.
function getold_val(fieldname,str){
var chunks=str.split("||");
var allchunks = chunks.length-1;
for(k=0;k<allchunks;k++){
var n=str.indexOf(fieldname);
alert(chunks[k]);
if(n>0){
var chunkd=chunks[k].split("::");
alert(chunkd);
return chunkd[1];
}
}
}
var test = getold_val('kid_2','date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||');
alert(test);
A regex may be a little more appealing. Here's a fiddle:
function getValue(source, key){
return (new RegExp("(^|\\|)" + key + "::([^$\\|]+)", "i").exec(source) || {})[2];
}
getValue("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","kid_2");
But if you want something a little more involved, you can parse that string into a dictionary like so (fiddle):
function splitToDictionary(val, fieldDelimiter, valueDelimiter){
var dict = {},
fields = val.split(fieldDelimiter),
kvp;
for (var i = 0; i < fields.length; i++) {
if (fields[i] !== "") {
kvp = fields[i].split(valueDelimiter);
dict[kvp[0]] = kvp[1];
}
}
return dict;
}
var dict = splitToDictionary("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","||","::");
console.log(dict["date_1"]);
console.log(dict["date_2"]);
console.log(dict["kid_1"]);
console.log(dict["kid_2"]);​
This works, here's my fiddle.
function getold_val(fieldname,str) {
var chunks = str.split('||');
for(var i = 0; i < chunks.length-1; i++) {
if(chunks[i].indexOf(fieldname) >= 0) {
return(chunks[i].substring(fieldname.length+2));
}
}
}
alert(getold_val('kid_2', 'date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||'));
The issue with your code was (as #slebetman noticed as well) the fact that a string index can be 0 because it starts exactly in the first letter.
The code is almost the same as yours, I just didn't use the second .split('::') because I felt a .substring(...) would be easier.
There are two bugs. The first error is in the indexOf call:
var n = str.indexOf(fieldname);
This will always return a value greater than or equal to 0 since the field exists in the string. What you should be doing is:
var n = chunks[k].indexOf(fieldname);
The second error is in your if statement. It should be:
if(n >= 0) {
...
}
or
if(n > -1) {
...
}
The substring you are looking for could very well be the at the beginning of the string, in which case its index is 0. indexOf returns -1 if it cannot find what you're looking for.
That being said, here's a better way to do what you're trying to do:
function getold_val(fieldName, str) {
var keyValuePairs = str.split("||");
var returnValue = null;
if(/||$/.match(str)) {
keyValuePairs = keyValuePairs.slice(0, keyValuePairs.length - 1);
}
var found = false;
var i = 0;
while(i < keyValuePairs.length && !found) {
var keyValuePair = keyValuePairs[i].split("::");
var key = keyValuePair[0];
var value = keyValuePair[1];
if(fieldName === key) {
returnValue = value;
found = true;
}
i++;
}
return returnValue;
}

Categories

Resources