the string is the name of some input fields. Examples:
a[b][c]
x[y][z][]
I'm trying to produce multidimensional arrays from it.
a.b.c = value
x.y.z = [value] (value is an array because of [])
anyway i have some ideas on how to do that but first I need to split the string into an array that contains all keys and subkeys.
Searching google I've come up with this
var parts = inputName.match(/[^\[\]]+/g);
it gets me [a,b,c], but on the 2nd example I get [x,y,z] instead of [x,y,z, null]
Any way I can also match [] and add it to the list as null ? I'm not that familiar with regular expressions
#AnnaK. Why can't you simply use ids and keys to send your
information? Is it a form that is dynamic in its size? Is it because
you're developing a framework that needs to be dynamic? Is it because
you're using a function multiple places? Can't you serialize it by
using the names? We can't give you suggestions because we still don't
know why you need to transfer it as an array (which would be
serialized anyway), and we still don't know what your form looks like
Because I'm trying to send the form data with Ajax. Also, before I send the data, I need to prepend a few fields that I create with javascript. I cannot serialize it, at least not with jQuery.serializeArray if that's what you meant, because if I have multiple keys like x[y][z][], only the last one will appear
You can use the following solution:
var parts = inputName.split(/[[\]]{1,2}/);
parts.length--; // the last entry is dummy, need to take it out
console.log(parts); // ["x", "y", "z", ""]
If you need the null value (because there is processing you have no control over for example) you can use this snippet to update the result (curtesy of #Ties):
parts = parts.map(function(item){ return item === '' ? null : item });
Basic idea I had was to look for a [] and than use map() to replace it with null.
("a[bb][c][]").match(/([^[\]]+|\[\])/g).map( function(val) { return val==="[]" ? null : val; });
Regex: ([^\[\]]|\[\])+
Will match:
a[b][c] // a, b, c
x[y][z][] // x, y, z
1[][2][][3][] // 1, [], 2, [], 3, []
Related
I am working with data from an api that is returning values formatted like this for a few of the keys:
"key_one": [
"[\"Some Value One\",\"Some Value Two\",\"Some Value Three\"]"
],
"key_two": [
"[\"Some Value Four\",\"Some Value Five\"]"
],
The values of the keys come back as an array, but the array contains just one long string. I am looking for a way for taking THIS:
["[\"Some Value One\",\"Some Value Two\",\"Some Value Three\"]"]
and turning it into THIS:
["Some Value One","Some Value Two","Some Value Three"]
I have a feeling Regex would be best for this, but I am still a complete novice with Regex and my attempts so far havent gotten me anywhere.
I also attempted to do a basic for loop that looked for the presence of the " mark, and then checked to see if the character after wasnt a ',' and tried to push or += the letters into a string and then into an array at the end to return, but it was becoming a mess and wasn't working either.
I am hoping someone here can show me a more elegant solution.....
You ca try JSON.parse
const obj = {
"key_one": [
"[\"Some Value One\",\"Some Value Two\",\"Some Value Three\"]"
],
"key_two": [
"[\"Some Value Four\",\"Some Value Five\"]"
]
}
for (let keys in obj) {
obj[keys] = JSON.parse(obj[keys])
}
console.log(obj)
In my react app I am tasked with sending multiple GET requests, sometimes with some optional filter params attached. Additionally I'm storing the params in my redux store so that they are able to stack on subsequent requests. Here's the problem: There are times when I'll clear the values of a param but since their keys are still saved to my store I'll get requests sent out like this:
/restaurants/?search=&state_id=2
Notice how the search param value is empty (as expected). I was wondering what would be the best approach in removing these type of lingering params? I looked into lodash's _.omitBy combined with _.isEmpty but this throws a sort of false positive in dealing with numeric values like pagination.
_.omitBy(params, ._isEmpty);
I didn't think that providing how exactly the params are via react/redux was necessary stored but am happy to provide it if it helps.
Note: I'm using axios and passing my params in as an object as opposed to a string:
axios.get('restaurants', {
params
});
Considering your params are stored in an object (as you mentioned in your latest edit), you can just remove properties containing empty strings:
const params = {
search: "",
state_id: 2
};
for (const key of Object.keys(params)) {
if (params[key] === "") {
delete params[key];
}
}
console.info(params);
This alternative has the advantage of being short and easy to maintain.
But for those with a string containing all params already serialized, it's easy to do using regular expressions:
function removeEmptyParams(query) {
return query.replace(/[^=&]+=(?:&|$)/g, "");
}
const testQuery = "f=1&search=&state_id=2&foo=&bar=12";
console.info(removeEmptyParams(testQuery));
Also very simple and easy to maintain.
The best and easiest way is to use a Spread Object literal on every optional param,
like this
params:{
...( CONDITION && {param_key: param_value}),
...( this.state_id != null && {state_id: this.state_id})
}
If condition is TRUE, the encapsulated key:value pair will be unwrapped, if condition is false , there will be no empty value or key.
You might need to parse that manually. Split on the & then split on the = and check if there's a value based on the length of the split - remove accordingly from there. If you're comfortable with regex you can check if there are values after the = instead of splitting.
This solution is a little crude, but it works. Let's assume your query params are stored in a Map, something like:
const params = {
foo: 'bar',
bang: 0,
buzz: '' // this value has been removed from your store
}
You could create an array of keys from your params Map, filter out the items that don't have a value and then join them all back together as query params.
const queryString = Object.keys(params).map(filter => {
if (params[filter] || Number.isInteger(params[filter])) {
return `${filter}=${params[filter]}`;
}
return null;
}).filter(item => item).join('&');
Which would result in foo=bar&bang=0
I've been struggling with this issue so I thought I'd come here to find the fix. I'm trying to filter my objects that are in an array to only show the ones that have for example "h" in them.
This is how my array of objects is being constructed:
Object.keys(data.jello).forEach(function (id, SomeSearchValue) {
var jello = data.jello[id];
array.push({
id: jello.id,
name: jello.name,
type: 'foo',
});
}
For example, let's say my array consists of this for names.
array[blue, red, green, apple, abigail, alien]
So, I have an array of objects. In a search bar I type "a" and my array results are then all objects that have a letter 'a' in the name. so...
array[abigail, alien]
Then i type a "b" so my search is now "ab" and my array is ...
array[abigail]
So what would my code to implement this using jQuery?
The part I'm stuck on most is the actual searching as the user types without using ajax.
I'm using jQuery. Ive tried things like jQuery.grep(), inArray() but cant seem to search includes. I've also tried array.includes(). Thanks for the help!
Use Array#filter().
jQuery $.grep() is basically the same thing but also works on jQuery objects.
Following assumes you only want to search within name property and will accept the term found in any part of the name rather than just at beginning
const data = [{name:'blue'}, {name:'red'}, {name:'green'}, {name:'apple'}, {name:'abigail'}, {name:'alien'}];
const term ='ab';
const filtered = data.filter(({name}) => name.toLowerCase().includes(term.toLowerCase()))
// or use startsWith() to only match beginning of string
console.log(filtered)
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.
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.