Robust String Split - javascript

I have a JavaScript function:
function doSomething(arg) {
var array = arg.split(',');
// etc...
}
arg is populated using jQuery's .data('myId') function.
Often, myId contains a comma separated list of integers and the code works great. However, if myId only contains a single integer, the code fails with the error
Object doesn't support property or method 'split'
Is there a compact, robust method to create the array without including if statements to handle the boundary conditions of one integer or an empty string?

attr will return a string, while data will try to parse the value and return an object with the "correct" type.
foo.attr('data-myId'); //pass this instead
You can't get around identifying an empty string without an if though. You either need to check for it, or for an array with a single empty string element.

You have two unrelated problems.
The first one is for case of empty string: Split will return a one-element array with an empty string. Just check for it and compensate.
var array;
if (arg == "") array = [];
If there is a single integer, I believe you are not getting a string from the .data(), but an actual integer; so first convert it into a string:
else array = String(arg).split(',');
Alternately, you could just avoid the jQuery magic, and access the attribute directly - all data() attributes are just attributes with data- prefixed.

.data will try to guess the type of the value based on its contents, so it becomes a number. You could use .attr, which always returns a string if it's available as an attribute. Alternatively, cast to a string:
('' + arg).split(',')
//or
String(arg).split(',')
I'm actually not sure whether one is preferred or not.
Also note that ''.split(',') returns [''] or an array with an empty string element. You can get around that with .filter(function (elem) { return elem !== ''; })
Another possible alternative is to use dataset on the element itself.

Related

replace() on variable not working

replace() is not working on a variable I've created representative of a bunch of names I'm deriving from a JSON object in a loop.
I understand strings are immutable in JS. I believe I have ruled that out.
for (object in Object.keys(json)) {
console.log(json[object]["senderProfile"]["name"])
var name_ = String(json[object]["senderProfile"]["name"])
var name = name_.replace(',', '')
names.push(name+"<br>")
}
document.getElementById("json_out").innerHTML = names;
The HTML that is rendered has commas in between each name. Not sure what to make of it.
names is an array. You are implicitly converting the array to a string. By default, array members are separated by comma. Simple example:
console.log('' + [1,2,3])
You can join array members with a custom separator by calling .join:
console.log('' + [1,2,3].join(''))
It may be possible to simplify your code, but not without knowing what the value of json or json[object]["senderProfile"]["name"] is. However, instead of appending <br> to the name, you could use it as the element separator:
var names = Object.keys(json)
.map(key => json[key]["senderProfile"]["name"]);
document.getElementById("json_out").innerHTML = names.join('<br>');

producing a word from a string in javascript

I have a string which is name=noazet difficulty=easy and I want to produce the two words noazet and easy. How can I do this in JavaScript?
I tried var s = word.split("=");
but it doesn't give me what I want .
In this case, you can do it with that split:
var s = "name=noazet difficulty=easy";
var arr = s.split('=');
var name = arr[0]; //= "name"
var easy = arr[2]; //= "easy"
here, s.split('=') returns an array:
["name","noazet difficulty","easy"]
you can try following code:
word.split(' ').map(function(part){return part.split('=')[1];});
it will return an array of two elements, first of which is name ("noazet") and second is difficulty ("easy"):
["noazet", "easy"]
word.split("=") will give you an array of strings which are created by cutting the input along the "=" character, in your case:
results = [name,noazet,difficulty,easy]
if you want to access noazet and easy, these are indices 1 and 3, ie.
results[1] //which is "noazet"
(EDIT: if you have a space in your input, as it just appeared in your edit, then you need to split by an empty string first - " ")
Based on your data structure, I'd expect the desired data to be always available in the odd numbered indices - but first of all I'd advise using a different data representation. Where is this string word coming from, user input?
Just as an aside, a better idea than making an array out of your input might be to map it into an object. For example:
var s = "name=noazet difficulty=easy";
var obj = s.split(" ").reduce(function(c,n) {
var a = n.split("=");
c[a[0]] = a[1];
return c;
}, {});
This will give you an object that looks like this:
{
name: "noazert",
difficulty: "easy"
}
Which makes getting the right values really easy:
var difficulty = obj.difficulty; // or obj["difficulty"];
And this is more robust since you don't need to hard code array indexes or worry about what happens if you set an input string where the keys are reversed, for example:
var s = "difficulty=easy name=noazet";
Will produce an equivalent object, but would break your code if you hard coded array indexes.
You may be able to get away with splitting it twice: first on spaces, then on equals signs. This would be one way to do that:
function parsePairs(s) {
return s.split(' ').reduce(
function (dict, pair) {
var parts = pair.split('=');
dict[parts[0]] = parts.slice(1).join('=');
return dict;
},
{}
);
}
This gets you an object with keys equal to the first part of each pair (before the =), and values equal to the second part of each pair (after the =). If a string has multiple equal signs, only the first one is used to obtain the key; the rest become part of the value. For your example, it returns {"name":"noazet", "difficulty":"hard"}. From there, getting the values is easy.
The magic happens in the Array.prototype.reduce callback. We've used String.prototype.split to get each name=value pair already, so we split that on equal signs. The first string from the split becomes the key, and then we join the rest of the parts with an = sign. That way, everything after the first = gets included in the value; if we didn't do that, then an = in the value would get cut off, as would everything after it.
Depending on the browsers you need to support, you may have to polyfill Array.prototype.reduce, but polyfills for that are everywhere.

Using javascript's indexOf on an array of svg text elements

I am working with an svg file which has a number of text elements within it. The text elements are all numbers. I am able to get the list of values and put them into an array with the following line of code.
var fretdata = document.getElementById("fretinformation").getElementsByTagName("text");
I am able to access .length property and also the access the array elements by index such as [0].textContent. However, when I try to use the .indexOf() function on the array, I receive an error message that the object (my array) does not support the property or method of indexOf.
I am able to setup a for loop to iterate through the array checking each value looking for the presence or absence of a certain value. I would like something with the simplicity of the indexOf functionality which tells me whether or not something is present within the array and where it is if present. Is there a to get .indexOf() working with the svg text element array? Or is there a similar alternative which does not require the use of loops and flags?
I think the problem lies in the fact that I have an array of text elements and not an array of strings. But I'm not sure how to directly get the array of the text element's textContent
var fretdata = document.getElementById("fretinformation").getElementsByTagName("text");
//var fretdata = document.getElementById("fretinformation").getElementsByTagName("text").textcontent;
//18th fret is the upper fret limit
//0 fret (open string) is the lower fret limit
//var zerolocation=fretdata.indexOf("0");
for (fd=0;fd<fretdata.length;fd++){
if(fretdata[fd].textContent=="0"){
document.getElementById("downkey").setAttribute("onclick",null);
document.getElementById("downkey").getElementsByTagName("polygon")[0].style.fill="#D3D3D3";
}
}
Iterating in the loop works. The two lines commented out using the .indexOf do not.
Thanks, --christopher
What you have is not an array, it's a nodeList.
A nodeList has length, and is array-like, but array methods like indexOf, forEach etc. doesn't work on nodeLists.
You can convert a nodeList to an array like this
var array = Array.prototype.slice.call(fretdata);
but in your case you really shouldn't, you should stick to the iteration instead.
Iterating the elements is really an option, but if you don't like it, you may have 2 more options depending on your setup:
The following code requires map function (check compatibility here, it basically requires IE9+) and slice function compatibility (same, IE9+).
var fretdata = document.getElementById("fretinformation").getElementsByTagName("text");
alert([].slice.call(fretdata).map(function(o) { return o.textContent; }).indexOf("1"));
The other one requires jQuery, it handles a lot of stuff for you.
alert($( "#fretinformation > text" ).filter(function() { return $(this).text() === "1"; } ).length);
use ES6 spread operators
var fretdata = [...(document.getElementById("fretinformation").getElementsByTagName("text"))]
This internally works as
var array = Array.prototype.slice.call(fretdata);

String to JavaScript Array

My Ajax call gets "[['Best Value (62)',62 ],['LPTA (32)',32 ],] " as the return value. I need to pass this as an array. Is there a way to make the string into an array without resorting to eval()?
If you get rid of the trailing comma and change the double quotes to escaped double quotes and anything else you have in the array is well formed then you can use JSON.parse to turn the string into an array. If you have access to the serverside code you'll likely want to make the changes there rather than in your js.
JSON.parse("[[\"Best Value (62)\",62],[\"LPTA (32)\",32]]")
JSON.parse("[['Best Value (62)',62 ],['LPTA (32)',32 ],]".replace(/(,])$/, ']').replace(/'/g, '"'))
What you have isn't JSON, but is valid JavaScript (assuming the extra comma was a copy-paste error). And, as much as I dislike it, you can use eval:
// convert the input in to a javascript array
var o = eval("[['Best Value (62)',62],['LPTA (32)',32]]");
// use jQuery map to grab only the first array value and return
// each selection back as an array
$.map(o, function(a){
return a[0];
}); // ['Best Value (62)','LPTA (32)'];
if the extra comma is there to stay, you can use a little more processing to get rid of it:
var data = "[['Best Value (62)',62],['LPTA (32)',32],]";
var o = eval(data.replace(/\],\]$/,']]'));
$.map(o, function(a){
return a[0];
});

How can I get a HTML data value as a string with jQuery?

I have the following in my source HTML:
<li>Test</li>
I want to get the value of the data attribute so I am using the following:
var abc = $(this).data('value');
This works okay BUT not if there is a leading zero. For example the above
placed the value "1" into abc.
Is there a way that I can get it not to convert the "01" into "1" ?
this.dataset.value;
// Or old school
this.getAttribute('data-value');
const a = document.querySelector("a");
console.log('Using getAttribute, old school: ', a.getAttribute('data-value'));
console.log('Using dataset, conforms to data attributes: ', a.dataset.value);
<ul>
<li>Test</li>
</ul>
Thanks to #MaksymMelnyk for the heads up on dataset
You can use the attr() operator of jQuery:
var abc = $(this).attr('data-value');
From the jQuery data() documentation, it appears that you have to use .attr() to prevent the automatic type conversion:
Every attempt is made to convert the string to a JavaScript value (this includes booleans, numbers, objects, arrays, and null) otherwise it is left as a string. To retrieve the value's attribute as a string without any attempt to convert it, use the attr() method. When the data attribute is an object (starts with '{') or array (starts with '[') then jQuery.parseJSON is used to parse the string; it must follow valid JSON syntax including quoted property names. The data- attributes are pulled in the first time the data property is accessed and then are no longer accessed or mutated (all data values are then stored internally in jQuery).
So, not to duplicate other answers, but rather to reinforce, the way to access the attribute without doing type conversion is:
var abc = $(this).attr('data-value');
$(this).attr('data-value');
This will return the string value with the leading 0.
have you tried?:
$(this).attr('data-value');
or
$(this).attr('data-value').toString();
Try :
this.data('value');
I think this is best way to get data attribute value.
<article id="electric-cars" data-columns="3"data-index-number="12314" data-parent="cars">
</article>
const article = document.querySelector('#electric-cars');
article.dataset.columns // "3"
article.dataset.index-number // "12314"
article.dataset.parent // "cars"

Categories

Resources