building a search from split(": ") and indexing it into object - javascript

In the below javascript, "this" refers to Car object and search_id refers to the input text field with an id of "search_input". So basically the user types in text in the field and a search occurs based on the input. Now I understand that the val() method is grabbing the user input string from the input field. However, I am not sure what the colon in the split() method is doing. I always thought the split() method just puts a comma delimiter when you pass in an empty string into it. And then it appears that the splitted variable holds an array of strings broken down from the input. However, why would we be passing in the first broken down string in the string array (splitted[0]) and the second string (splitted[1]) and then passing that into the variable string_to_scope? Basically it is in the process of building a search. And it's these three lines I'm not sure what's going on:
var splitted = jQuery(this.search_id).val().split(": ");
if (splitted[0] && splitted[1]){
if (string_to_scope[splitted[0]]) ret[string_to_scope[splitted[0]]] = splitted[1];
Here's more context:
Car.prototype.filter_func=function(){
var ret={};
var string_to_scope = {
'Year': 'year_num_eq',
'Make': 'make_name_eq',
'Description': 'description_eq',
'Expiry': 'expires_on_eq'
};
var search_value = jQuery(this.search_id).val();
if(search_value != null && search_value.length > 0){
var splitted = jQuery(this.search_id).val().split(": ");
if (splitted[0] && splitted[1]){
if (string_to_scope[splitted[0]]) ret[string_to_scope[splitted[0]]] = splitted[1];
}
}
return ret;
};
Thanks for any response.

// 'Year: 1998' -> ['Year', '1998'];
var splitted = jQuery(this.search_id).val().split(": ");
// if there were two parts
// (the year is not missing)
if (splitted[0] && splitted[1]){
// if the key exists in string_to_scope object
// -> ok because string_to_scope['Year'] exists
if (string_to_scope[splitted[0]])
// ret[ string_to_scope['Year'] ]
// -> ret['year_num_eq'] = '1998';
ret[ string_to_scope[splitted[0] ] = splitted[1];

The idea is to allow someone to enter a search that looks like "Make: Toyota". That is to say, to make a single search box accommodate searches across multiple fields (where you specify which field). A more typical approach would be to have a drop-down for search type that is separate from the search term; this is trying to combine them into one box.
The "split" method takes a string that contains a delimiter and turns it into an array that contains everything before, between, or after the delimiter. In this case it's turning
"Make: Toyota" into ["Make","Toyota"].
The first piece (the search type) becomes the key into the scope hash, and the second piece becomes the search term.

Split does just like it sounds. Splits a string by the input and returns an array. So that is what is happening with the split.
jQuery(this.search_id).val().split(": ");
Then they are checking if there are values set for both the first index and the second.
if (splitted[0] && splitted[1])
If that is true then they are checking if the first value matches the name of a property in the string_to_scope object. You can access object properties by index similar to an array.
if (string_to_scope[splitted[0]])
If there is a property by that name then they are returning a new object ret with a property of the first split value that equals the second split value.
ret[string_to_scope[splitted[0]]] = splitted[1];

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>');

Javascript create a mapping of array values

I am working on a project where I give a user the ability to create their own email templates and insert tags into them as placeholder values that will eventually replaced with content.
The tags are in the format of [FirstName] [LastName]
I am trying to figure out the best approach to create a function that maps these tags to their values.
For example (Psuedo code):
function convertTags(message){
// Convert all instances of tags within the message to their assigned value
'[FirstName]' = FirstNameVar,
'[LastName]' = LastNameVar
// Return the message with all tags replaced
return message;
}
I assume I could do something like the following:
function convertTags(message){
message = message.replace(/[FirstName]/g, FirstNameVar);
message = message.replace(/[LastName]/g, LastNameVar);
return message;
}
I am just trying to come up with a clean way to do this, preferably in an array/mapping style format that I can easily add to.
Any recommendations on achieving this?
You're on the right lines. You just need to generalise your REGEX to match all params, not specifically 'firstname' or some such other hard-coded value.
Let's assume the replacers live in an object, replacers.
var replacers = {
'foo': 'bar',
'something-else': 'foo'
};
And here's our template:
var tmplt = 'This is my template [foo] etc etc [something-else] - [bar]';
For the replacement, we need iterative replacement via a callback:
tmplt = tmplt.replace(/\[[^\}]+\]/g, function(param) { //match all "[something]"
param = param.replace(/\[|\]/g, ''); //strip off leading [ and trailing ]
return replacers[param] || '??'; //return replacer or, if none found, '??'
});
The value of tmplt is now
This is my template bar etc etc foo - ??
Let's say you have an object like this:
var tagMapper: {};
In this object you can add anything you want as key-value pairs, example:
function addTag(key, value){
key = "__prefix__" + key;
tagMapper[key] = value;
}
addTag("key1", "value1");
The difference between an object and an array in javascript is that one uses named indexes while the other uses numbered indexed to set and retrieve data.
Now every time your user adds a new tag, you just add a new key-value pair to this object by calling the addTag function, then to replace those keys in your template just loop over the object as such:
for (var key in tagMapper) {
if (tagMapper.hasOwnProperty(key)) {
template = template.replace(key, tagMapper[key]);
//key here has value "__prefix__key1" and maps to "value1" from our example
}
}
The prefix was added to ensure the script doesn't replace an undesirable string from our template. Your tag format may be sufficient if you are sure the template doesn't contain any [] tags containing the same key as one in the tagMapper object.

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.

Robust String Split

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.

How to set certain element values to null in JavaSctipt

I have some items I am storing in an element that get added at various times like this:
document.getElementById('rout_markers').value = str;
I am not too good with JavaScript, but as I understand it, the values get stored as an array, correct?
What I need to do is to be able to remove all the elements or to be able to remove the last element that was added.
How can I do that?
Thanks!
If you're assigning str to an element then there are no arrays involved here - you'll be overwriting each previously-assigned value with the latest and thereby storing only the latest value.
You could use an array but you'd have to know the location of each item in the array, so if you wanted to assign or nullify a specific element in your array, you'd have to a have a record of where it was - although you could get around that it with a multi-dimensioned array, where the first element at each index is the name of the property, and the second element at each index is that value of the property.
If you want to store multiple properties in a field in order to retrieve them all later, there are two simple ways of doing this.
Consider using either a field for every property.
If you do this then I'd suggest using a naming convention for the fields so that you can more easily assign the property.
Concatenating a string to form a collection of key-value pairs, very much like a query-string.
In the example you gave, this would mean storing something like:
var keyVals = 'route_markers' + '=' + str + '&';
document.getElementById('myHiddenProperties').value = keyVals;
When you want to assign another property to this string you do something like this:
keyVals = document.getElementById('myHiddenProperties').value;
keyVals += 'new_property' + '=' + myNewValue + '&';
document.getElementById('myHiddenProperties').value = keyVals;
In this way, if you want to remove a specific key-value pair, you split the stored value like this
var arrKeyVals = document.getElementById('myHiddenProperties').value.split('&');
You then have an array of key-value pairs.
If you want to retrieve a value from this array, or blank one of the values then loop through this array, splitting each into its key and value, like this:
for (var i = 0; i < arrKeyVals.length; i++) {
var keyVal = arrKeyVals[i].split('=');
var key = keyVal[0];
var val = keyVal[1];
if (key == name_of_key_sought) {
val = ''; //assign an empty string to this property to forget about it
}
}
I am not too good with JavaScript, but as I understand it, the values get stored as an array, correct?
No, the value property of certain HTML elements is just a string value. (And it only exists on certain elements, like input.) Assigning a new value to value will overwrite the previous value, not store it in an array.
What I need to do is to be able to remove all the elements or to be able to remove the last element that was added.
This part of the question sort of goes away because of the answer to the first part, but you can clear the value property by assigning an empty string to it.
If by any chance you mean remove/hide the element itself (the text box) then you can have such code:
document.getElementById('rout_markers').style.display = 'none';
Otherwise the other answers here cover it all nicely.

Categories

Resources