$.inArray is giving -1? - javascript

This should be pretty straight forward:
HTML
my link
<input type="hidden" id="pageids" value="28,27,26,17,18,19,">
Jquery
var thumbaid = $('#thumba').data("id");
// get position
var itemids = $('#pageids').val();
var itemids_array = itemids.split(',');
var currentpos = $.inArray(thumbaid, itemids_array );
alert(currentpos);
Gives me -1?
The funny thing is that if I replace " $(thumba).data("id")" for a number in the jquery code as "26", it works!
The result should be, in this case, "2".
Any ideas?

You need to convert the value to a string.
var thumbaid = $('#thumba').data("id").toString();
Why...? If you were to
console.log(itemids_array);
you would see this
["28", "27", "26", "17", "18", "19", ""]
They are not numbers, they are strings. See http://api.jquery.com/data/

That is because the thumbaid is a number, and the itemids_array contains strings. Try var currentpos = $.inArray(thumbaid.toString(), itemids_array );
jQuery's data function reads the data- attributes and parses digits to numbers.

jQuery's data function does things to the data it reads from the data-* attributes on initialization, including turning number-like strings into numbers. Since $.inArray does an === check, that's why it fails. You end up looking for the number 26 in an array of strings.
If you simply use .attr("data-id") instead, the conversion won't happen.
This behavior is documented in the data docs:
Every attempt is made to convert the string to a JavaScript value (this includes booleans, numbers, objects, arrays, and null). A value is only converted to a number if doing so doesn't change the value's representation. For example, "1E02" and "100.000" are equivalent as numbers (numeric value 100) but converting them would alter their representation so they are left as strings. The string value "100" is converted to the number 100.
If you're only using data to read data-* attributes, I recommend using attr instead to avoid this kind of thing, and to avoid the confusion caused by the fact that while data initializes from data-* attributes, it doesn't write to them when you set data. Of course, if you need to store data associated with elements and you don't want it on an attribute (because it's not string data, or you don't want it showing in the DOM inspector), data is the right tool for that job.

The reason its not working, is because jQuery data is returning an int not string.
See this example.
my link
<input type="hidden" id="pageids" value="28,27,26,17,18,19,">
Javascript:
var thumbaid = $('#thumba').data('id').toString();
// get position
var itemids = $('#pageids').val();
var itemids_array = itemids.split(',');
console.log(itemids_array);
var currentpos = $.inArray(thumbaid, itemids_array );
console.log(currentpos);

$().data() will convert the data-* attribute's value to a JavaScript value. In your case, thumbaid is converted to a number.
$.inArray compares elements using the strict equality operator(===). That is, '26' === 26 returns false as no type coercion occurs.
From the jQuery.data() docs:
Every attempt is made to convert the string to a JavaScript value
(this includes booleans, numbers, objects, arrays, and null). A value
is only converted to a number if doing so doesn't change the value's
representation. For example, "1E02" and "100.000" are equivalent as
numbers (numeric value 100) but converting them would alter their
representation so they are left as strings. The string value "100" is
converted to the number 100.

Related

String to JSON parse issue with number conversion

Hi Here I am using JavaScript to convert string to Json object,Here below my code
const json = '{"result":true, "count":42,"groupID": 80000000000000809}';
const obj = JSON.parse(json);
console.log(obj);
result is
Object { result: true, count: 42, groupID: 80000000000000820 }
but required output is
{ result: true, count: 42, groupID: 80000000000000809 }
Why the groupID value is changing during the conversion.Please help me to resolve this.
Thanks for your response.
I have found solution for this.
const json = '{"result":true, "count":42,"groupID": 80000000000000000809}';
const obj = JSON.parse(json.replace(/("[^"]*"\s*:\s*)(\d{17,})/g, '$1"$2"'));
console.log(obj);
The above code I have used string replace method to replace big-integer into string.
The integer you are trying to parse is too large. JavaScript only supports up to 53-bit integers, so the maximum value for a Number type in JavaScript is +/- 9,007,199,254,740,991. Any larger and you'll need to use a BigInt. See here for how to work with large integers in JavaScript.
I would recommend changing groupID in your API response to a string rather than an integer.
If you can't do this, then you could also try using a JSON parsing library that can handle BigInt types, e.g. json-bigint.
You can always check Number.MAX_SAFE_INTEGER(). Let's compare this result with the number you're working with:
9007199254740991
80000000000000826
Your number appears to be over the technical maximum that JavaScript supports with integers. I tested with a few other numbers, they appear to have similar problems. Documentation...
The Number.MAX_SAFE_INTEGER constant represents the maximum safe integer in JavaScript (253 - 1).
For larger integers, consider using BigInt. (Source: MDN Web Docs: Number.MAX_SAFE_INTEGER
You can always use a string, though, since it is likely that you'll actually be getting this JSON from a web-server, rather than locally defined:
const json = '{"result":true, "count":42,"groupID": "80000000000000809"}';
const obj = JSON.parse(json);
console.log(obj);

convert array stored in a string to an array

I have an array value which is coming from database as an string. I need to convert it into an array. When I check my value in console I can see value as
"[["COL1","COL2","COL3"],["COL4","space,"COL5"]]"
In order to perform my operations I need it to be in below structure
[["COL1","COL2","COL3"],["COL4","space,"COL5"]]
I have already tried JSON.parse() and parseJSON
Expected Result :
[["COL1","COL2","COL3"],["COL4","space,"COL5"]]
Actual Result :
"[["COL1","COL2","COL3"],["COL4","space,"COL5"]]"
You need to remove the outer quotes from your string, then pass the value to JSON.parse() to get the array.
Also, you have to quote each item correctly, "space should be "space".
You can sanitize the string with String.prototype.replace() (assuming the quoting of space has been fixed in the DB):
const data = '"[["COL1","COL2","COL3"],["COL4","space","COL5"]]"';
const dataSanitized = data.replace(/^"|"$/g,"");
console.log(JSON.parse(dataSanitized));
I would suggest you do parse
JSON.parse('[["COL1","COL2","COL3"],["COL4","space","COL5"]]')
i would not suggest eval as i just read an article about "how eval is evil"
https://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/

Is it possible to store integer value in localStorage like in Javascript objects and extract it without typecasting?

When I assign integer value to localStorage item
localStorage.setItem('a',1)
and check its type
typeof(localStorage.a)
"string"
it returns string, I can typecast it to int for my use
parseInt(localStorage.a)
My question is it possible to store integer value inside localStorage as I can do for Javascript objects without typecasting?
a={};
a.number=1;
typeof(a.number)
"number"
My question is it possible to store integer value inside localStorage as I can do for Javascript objects without typecasting?
No.
Storage objects are simple key-value stores, similar to objects, but they stay intact through page loads. The keys can be strings or integers, but the values are always strings. [source]
Actually you can, if we agree that parsing is not the same as typecasting :
let val = 42;
localStorage.answer = JSON.stringify(val);
let saved = JSON.parse(localStorage.answer);
console.log( saved === val ); // true
Fiddle since over-protected stacksnippets don't allow localStorage.
For simplicity, you should anyway always stringify to JSON what you are saving in localStorage, this way you don't have to think about what you are saving / retrieving, and you will avoid "[object Object]" being saved.
You can store in numeric format using:
localStorage.setItem('object', JSON.stringify({
//Insert Number(value)
number: Number(1)
}));
// After get item
var object = localStorage.getItem('object');
console.log(JSON.parse(object));
Yes, you can store an integer in localStorage, but since it will be converted into a string, how do you actually know it was an integer? The question is not rhetorical. Storing an integer in localStorage is one thing (and easily accomplished), but knowing it's supposed to be an integer when you retrieve it is a different matter altogether. Not only do you have to keep track of the storage key value, you must also keep track of the data type.
What we really want is a mechanism that allows us to treat storage almost the same way we treat variables. If I am working with an integer, a float, a bigint, a string, a date, an array, a Boolean or an object then we would like to shove it into localStorage and get it back out. No conversion. No muss and no fuss.
This is precisely what localDataStorage does. (NOTE: I am the author.) The library transparently sets/gets key values using data "types" such as Array, BigInt, Boolean, Date, Float, Integer, Object and String. Store an integer, get it back. Working with dates, bigints or floats? No problem. And if you need to store arrays in localStorage, you can easily do so, as well as add and remove elements. Again, localDataStorage does all the heavy lifting for you. Let's have a look:
Include the library:
<script src="https://cdn.jsdelivr.net/gh/macmcmeans/localDataStorage#master/localDataStorage-2.0.1.min.js"></script>
Instantiate a namespaced copy:
const lds = localDataStorage( 'myapp-storage' );
Toss an integer in storage...
lds.set( 'myIntKey', 467 );
and get it back out:
let myInt = lds.get( 'myIntKey' );
console.log( myInt );
> 467
Ensure the data type was preserved:
typeof myInt;
> "number"
You can also check data types with the library:
lds.showtype( 'myIntKey' );
> "integer"
lds.isinteger( 'myIntKey' );
> true
lds.isnumber( 'myIntKey' );
> true
And of course we have some helper functions:
lds.haskey( 'myIntKey' );
> true
lds.hasval( 467 );
> true
lds.hastype( "integer" );
> true
The library also 1) provides lightweight data obfuscation; 2) intelligently compresses strings (to save storage space); 3) facilitates robust lookup including query by key (name), query by (key) value and query by existence (boolean check); 4) enforces segmented shared storage within the same domain by prefixing keys; and 5) responds to localStorage change events on the same page/tab that fired them. [/end glossyBrochure]

AngularJS orderBy using lexicographical ordering even with numbers

I have a value function which is passed into my orderBy as:
function getValue(item){
return [parseInt(item.approx_value_usd) || -1];
}
This definitely always returns a number array, but for some reason on the front-end AngularJS always orders my items by lexicographical order of the property 'approx_value_usd' e.g.
88 > 82 > 8 > 53 (wrong!)
I feel like I'm missing something but can't seem to get anywhere with this problem.
The return value of the "order-by" function is examined using simple comparisons. Your code is returning an array, not just a number. When an array appears in a JavaScript > or < comparison, it'll be converted to a string. That's done by taking the string value of each element in the array and joining them.
Thus, even though you were putting numbers in the array, when Angular actually used the returned value it ends up being a string anyway. If you drop the [ ] it should work.

Data-attribute retrieval and parsing javascript

I am new to javascript programming and i am stuck with data-attribute retrieval.
The below link is a bit useful for people using jQuery
store and retrieve javascript arrays into and from HTML5 data attributes
I would like to do the same with vanilla js. With the help of custom data-attributes i would like to create objects & array.
<div id="getAnimation"
data-r="564"
data-c="96"
data-custom="x:0;y:0;z:0;rotationX:0;rotationY:0;rotationZ:0;scaleX:0.75;scaleY:0.75; skewX:0;skewY:0;opacity:0;transformPerspective:600;transformOrigin:50% 50%;"
data-s="700"
data-st="1400"
</div>
Do HTML5 custom data attributes “work” in IE 6?
The above link helps in getting data attributes very well but how can be filter the string in data-custom or straight create an object of data-custom.
If someone know a library to do this please let me know
Here are a couple quick functions which will let you store, retrieve and delete any JSON-able data to a data attribute
function setData(node, data_name, data_value) {
node.dataset[data_name] = JSON.stringify(data_value);
}
function getData(node, data_name) {
return JSON.parse(node.dataset[data_name]);
}
function delData(node, data_name) {
return delete node.dataset[data_name];
}
Then to write an Array to #getAnimation in data-fizz
// variables to use
var elm = document.getElementById('getAnimation'),
foo = [1, 2, 3, 'a', 'b', 'c'];
// store it
setData(elm, 'fizz', foo);
// retrieve it
var bar = getData(elm, 'fizz');
// look what we have
console.log(bar); // [1, 2, 3, "a", "b", "c"]
Requires IE 11+ because I use node.dataset, if you change this to the methods node.setAttribute, node.getAttribute and node.removeAttribute as used, the requirement drops to IE 8+ because of the JSON.stringify and JSON.parse
That particular example is quite straight forward: It's a series of name:value pairs separated with semicolons. So you can get an array of the pairs using split, and then get the name and valid separate using split again. If you want to create properties on an object using those names and values, you can do that with bracketed notation:
// Get the value
var val = theElement.getAttribute("data-custom");
// Split it into fields on `;` (with optional whitespace on either side)
var fields = val.split(/\s*;\s*/);
// Create a blank object
var obj = {};
// Loop through the fields, creating object properties:
fields.forEach(function(field) {
// Split the field on :, again with optional whitespace either side
var parts = field.split(/\s*:\s*/);
// Create a property on the object using the name, and assigning the value
obj[parts[0]] = parts[1];
});
I'm using String#split there, giving it a regular expression to tell it where the split up the string.
In the resulting object, with just the code above, the property values will all be strings. For instance, obj.scaleX will be the string "0.75". If you need them as numbers, you can convert them to numbers in any of several ways:
parseFloat, which will convert as many characters as it can but ignore trailing characters. so parseFloat("0.75foo") is 0.75, not an error.
Number, which will not be tolerant like parseFloat, Number("0.75foo") is NaN, not 0.75.
Applying any mathematical operator, the unary + is common: +"0.75" is 0.75.
So rather than just grabbing the values as strings, we could check to see if they look like they might be numbers and convert them if so:
// Loop through the fields, creating object properties:
fields.forEach(function(field) {
// Split the field on :, again with optional whitespace either side
var parts = field.split(/\s*:\s*/);
// Does the value look like a number?
if (/(?:^\d+$)|(?:^\d+\.\d+$)/.test(parts[1])) {
// Yes
obj[parts[0]] = +parts[1];
}
else {
// No
obj[parts[0]] = parts[1];
}
});
That assumes . as the decimal separator, and assumes there won't be a thousands separator.
Side note: Above I've used Array#forEach, which is an ES5 feature not present on older browsers. forEach can be "shimmed" on older browsers, though. You can see all sorts of ways of looping through arrays in this answer here on SO.

Categories