Vue JS - Using URLSearchParams is showing me error - javascript

I have an object and I need to pass it to the ajax request.
advanceSearch(e, field) {
this.searchString.push({
[field] : e
});
let q = new URLSearchParams(this.searchString).toString();
// this.searchTerm = e;
http.get('projects/search/'+q)
.then( ( response ) => {
console.log( response )
})
.catch( ( error ) => {
});
},
Here thissearchString is an array of object. I need to pass this array of object to the URL. So, I am using URLSearchParams but got this error message:
TypeError: Failed to construct 'URLSearchParams': The object must have a callable ##iterator property

I think you not understand the function of URLSearchParams.
Here, what this function do:
const paramsString = "myquery=value&topic=api"
const searchParams= new URLSearchParams(this.searchString)
// Convert the string into a URLSearchParams, this allow multiples methods on it.
With that you can apply multiple function, the common is to use it like that:
// const searchParams= new URLSearchParams(this.searchString)
for (let p of searchParams) {
console.log(p);
}
Output:
- ['myquery', 'value']
- ['topic', 'api']
Relative to https://developer.mozilla.org/fr/docs/Web/API/URLSearchParams
If i see your code, you want exactly the opposite of that.
You can easly do that like that:
const paramsString = {
myquery: 'value',
topic: 'api'
}
Object.entries(paramsString).map(params => `${params[0]}:${params[1]}`).join('&')
// Object entries define a value and a key. You map on that and got params[0] wich is a key and params[1] the value.
// In map you return a string and receive a array with ['key:value']
// You join all array to convert in a string and set a & between
output:
- 'myquery:value&topic:api'
With a array of object:
const paramsString = [{ id : 1 }, { brand : 'bata' }, { price : 123} ]
const result = paramsString
.map((params) =>
Object.entries(params).map(
(keyValue) => `${keyValue[0]}:${keyValue[1]}`
)
)
.join('&')
// You got each object on map
// Convert him to key & value like before and return a array with string
// Join each array with '&'

Related

How to add a number to the name of an item that already exists in a json object before adding it to the object

Basically, I have an JSON Object named map, to which I add a key and value whenever it is needed for temporary storage.
So I need a function that checks if the key already exists in map and if it does exist then it adds a number to end of the key's name like _(number) and the number increases for every duplicate.
i.e (Just an example, I'm using the map for different purposes)
{
"hello": "world",
"hello_(1)": "do you like pizza?",
"hello_(2)": "https://google.com/"
}
Please do help me, Thanks!
Try to use Map.
(almost) One liner
Here is a short snippet:
var myMap = new Map();
myMap.has("hello") ? myMap.get("hello").push("newValueForHello") : myMap.set("hello", ["newValueForHello"])
Multi lines
The above is not very readable so I'll also add a more readable snippet but does the exact same thing
// Create the map instance
var myMap = new Map();
// if the map instance already has a "hello" key
if(myMap.has("hello") {
// get the key (which must be an array) and push the new value to the array.
myMap.get("hello").push("newValueForhello")
} else {
// if the map doesn't have the "hello" key, the add an empty array.
myMap.set("hello", ["newValueForHello"])
}
As a function
Here it is as a function..
function addItemToMap(mapObj, key, value) {
// if the key doesn't exist yet..
if(!mapObj.has(key)) {
// initialize it to an empty array.
mapObj.set(key, [])
}
// At this point the key must exist, and it must be an array, so just push a new item to the array.
mapObj.get(key).push(value)
}
// usage
var myMap = new Map()
addItemToMap(myMap, "hello", "first hello item")
addItemToMap(myMap, "hello", "second hello item")
Here is a solution to your question:
const myDictionary = {
"hello": "hello",
"bye": "bye"
}
const addItemToDictionary = (newKey, newVal, dict) => {
const keyRegExp = new RegExp(`^${newKey}\.*`)
const keyCount = Object.keys(dict).filter(key => keyRegExp.test(key)).length;
return ({
...dict,
[`${newKey}_(${keyCount})`]: newVal
})
}
console.log(
addItemToDictionary('hello', 'hello yet again',
addItemToDictionary('bye', 'bye again',
addItemToDictionary('hello', 'hello again', myDictionary)
)
)
);
Bare in mind there is a lot of edge cases that you can have, eg. your new key can be 'hell' and it will break this solution (this is just one of many).
In such a situations as an engineer you should rethink your approach.
I would suggest instead of adding new elements to json as you asked you can simply change data structure interface:
const myDictionary = {
"hello": "hello",
"bye": "bye"
}
const addItemToDictionary = (newKey, newVal, dict) => {
const dictEntry = Object.keys(dict).find(key => key === newKey);
return ({
...dict,
[newKey]: dictEntry ? [...[dictEntry], newVal] : newVal
})
}
console.log(
addItemToDictionary('hello', 'hello yet again',
addItemToDictionary('bye', 'bye again',
addItemToDictionary('hello', 'hello again', myDictionary)
)
)
);

JS using dot, string notation to map nested and assign errors

Ok, this is an odd one that I just can't seem to get right.
I have a large, complex object to send to a backend. After various attempts, I tried using Joi to validate the schema, and I like it, but passing the errors back to the inputs is a nightmare
The body is subdivided into 5 sections, with each subsection containing between 10-30 fields, some of which are string[], interface[], number[], or general nested interfaces.
I tried writing my own custom validation and the complexity grew outta control.
(I know some of you are thinking "your schema is too complex" and you're right, but its not something I can change right now. Clients blah blah.)
The problem: Joi.validate(myBody) gives me a bunch of errors in the following format:
[ // <- error.details
{
context: {},
message: "X is not allowed to be empty",
path:["path","to","property"], // <- this is the key
type: ""
}
]
How can I map error.details to create a new validation object that I can then use for the form items themselves.
For example:
path = ["path","to","property"] // -> map over to create
let newObj = {
path:{
to: {
property: ""
}
}
}
I hope this make sense.
I want to take an array of vallidation errors, and turn them into a validation object that matches the initial object
The simplest approach IMO would be to use reduce to reverse create the object from the array
["path","to","property"].reduceRight((prev, current) => {
const obj = {};
obj[current] = prev
return obj;
}, "");
This will create the object as described in the original question. You need to use reduceRight rather than reduce so that you create the leaf node first otherwise you have having to try and traverse the graph each time you add a new node and you have to handle setting the leaf node to be a string rather than an object.
Extrapolating out what you are trying to achieve I'm assuming a couple of things:
You want to return a single object rather than an array of objects.
The leaf is likely to be the message.
There will only be a single error message for each path (because it makes life easier).
We can expand upon the above with the deep merge solution from here to create an object to return. The code for that would look like:
const errors = [ // <- error.details
{
context: {},
message: "X is not allowed to be empty",
path:["path","to","property"], // <- this is the key
type: ""
},
{
context: {},
message: "X has to be greater than 0",
path:["path","to","another", "property"], // <- this is the key
type: ""
}
]
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
function mergeDeep(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return mergeDeep(target, ...sources);
}
errors.map((e) => e.path.reduceRight((prev, current) => {
const obj = {};
obj[current] = prev
return obj;
}, e.message)).reduce((previous, current) => mergeDeep(previous, current), {})
The output from running errors through it would be:
{
path: {
to: {
property: 'X is not allowed to be empty',
another: { property: 'X has to be greater than 0' }
}
}
}
Problem statement being used
I want to take an array of vallidation errors, and turn them into a validation object that matches the initial object
Given: an array of strings (each of which is a prop)
Expected result: an object structured based on the array
Code Snippet
// given an array of props
// starting at root-level & ending at the leaf
const pList = ['root', 'lev1', 'lev2', 'propName'];
// method to transform array into an object
const transformToObj = arr => (
arr
.reverse()
.reduce(
(fin, itm) => ({ [itm]: fin ? {...fin} : '' }),
false
)
);
// test with given array
console.log(transformToObj(pList));
// test with user-input array (comma-separated)
console.log(transformToObj([...(
(prompt('Enter comma-separated path like a,b,c,d'))
.split(',')
.map(x => x.trim())
)]));
Explanation
first reverse the array (so the first item is the inner-most prop)
use .reduce to iterate
at each level, add the item as the outer-prop and the value as the existing object
if this is the inner-most prop, simply add an empty string as value

How does this sorting function in js is working?

In Next.js site (here https://nextjs.org/learn/basics/data-fetching/implement-getstaticprops), this example :
import path from 'path'
import matter from 'gray-matter'
const postsDirectory = path.join(process.cwd(), 'posts')
export function getSortedPostsData() {
// Get file names under /posts
const fileNames = fs.readdirSync(postsDirectory)
const allPostsData = fileNames.map(fileName => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '')
// Read markdown file as string
const fullPath = path.join(postsDirectory, fileName)
const fileContents = fs.readFileSync(fullPath, 'utf8')
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents)
// Combine the data with the id
return {
id,
...matterResult.data
}
})
// Sort posts by date
return allPostsData.sort(({ date: a }, { date: b }) => {
if (a < b) {
return 1
} else if (a > b) {
return -1
} else {
return 0
}
})
}
In this example the return value of function getSortedPostsData() is a sorted list of allPostsData. Posts are sorted on the basis of date.
My question is how the array is being sorted ?
The sort function is taking two arguments {date:a} , {date:b}.
Is it automatically converting the arguments to Date Object as the a.date and b.date are strings
This answer shows which sorting algorithm is used for each situation.
It is not automatically converting the arguments to Dates. That must be done beforehand. If you say that Date a and b are strings, they will be compared lexicographicaly according to the callback provided to the sort function.

How can I replace an item in an array with an object?

album.songs = [1234545, 43524];
const replaced = album.songs.map( e => { e = Object.assign({}, { _id : 123 }) } );
Output: undefined
My problem is that I would like to replace my items in 'songs' array with a specific object. It works with strings or numbers but not with objects.
Some notes:
With map, you return the object you want the new array to contain. Assigning to the parameter e just changes the value of the parameter, which isn't retained anywhere.
There's no need for Object.assign there, just create the object directly, so:
const replaced = album.songs.map(e => { return { _id : e }; } );
or the concise form:
const replaced = album.songs.map(e => ({ _id : e }) );
Note that since we want to return an object created with an object initializer, and the { in the initializer would start a function body, we wrap the value we want to return in ().
We can even take advantage of shorthand property notation if we change the name of the parameter to _id:
const replaced = album.songs.map(_id => ({ _id }) );
Live Example:
const album = {songs: [1234545, 43524]};
const replaced = album.songs.map(_id => ({ _id }) );
console.log(replaced);
You don't assign to the function parameter, since it only exists for that function, and it's not like you're dereferencing a pointer.
Just return the object. An arrow function automatically returns its expression if you don't use curly braces to denote the body.
var songs = [1234545, 43524];
const replaced = songs.map(e => ({_id: e}));
console.log(replaced);
Map function expects you to return a value for each iteration:
console.log([1, 2].map(n => n * 2))
In your case, it should be:
album.songs.map( e => ({ _id : e }))

Converting an array of objects in to a single object

Have an array which contains a no of json .
[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]
Note that each Json have same key . I want to convert this array into a single json like
{linkValue1:"value1",linkValue2:"value2",linkValue3:"value3",linkValue4:"value4",linkValue5:"value5"}
one thing i also need to know . my array is also inside a json how i get this arry from that json ?
My initial json is
{name:"value",age:"value",linkValue:[[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]
]}
I'm expcting my final json look like :
{name:"value",age:"value",linkValue1:"value1",linkValue2:"value2",linkValue3:"value3",linkValue4:"value4",linkValue5:"value5"}
can anyone please help me
Use Array.forEach and add properties to an empty object:
let source = {name:"value",age:"value",linkValue:[[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]]};
// Copy the array in a variable
let yourArray = source.linkValue[0];
// Delete the original array in the source object
delete source.linkValue;
yourArray.forEach((item, index) => {
source["linkValue" + (index + 1)] = item.linkValue
});
console.log(source); // Should have what you want
Using reduce API,
let targetObj = srcArr.reduce((accumulator, value, index)=>{
accumulator['linkValue'+(index+1)] = value.linkValue;
return accumulator;
}, {});
[{linkValue:"value1"},{linkValue:"value2"},{linkValue:"value3"},{linkValue:"value4"},{linkValue:"value5"}]
This is javascript Array contains multiple javascript object.
{linkValue1:"value1",linkValue2:"value2",linkValue3:"value3",linkValue4:"value4",linkValue5:"value5"}
If you need structure like this,Then define a single javascript object and add linkvalue1,linkvalue2 etc. as a member of that object and then add it to javascript Array.
Give this a try.
myObj.linkValue = myObj.linkValue.map((obj, index) => ({ [`linkValue${index + 1}`]: obj.linkValue }))
Solution with reduce
// HELPER FUNCTIONS
// pick properties from object with default value
function pick (props, sourceObj, defaultValue) {
return props.reduce(
(obj, prop) =>
Object.assign(obj, { [prop]: sourceObj[prop] || defaultValue }),
{}
)
}
// get property value or default
function propOr (propName, obj, defaultValue) {
return obj[propName] || defaultValue
}
// flatten nested array
function flattern (nestedArray) {
return nestedArray.reduce((flat, innerArray) => flat.concat(innerArray), [])
}
// LINKS BUILDER based on REDUCE
function buildLinks (linksArray) {
return linksArray.reduce((accumulator, item, index) => {
accumulator['linkValue' + (index + 1)] = item.linkValue
return accumulator
}, {})
}
// TRANSFORMATION FUNCTION - takes json and produce required output
function transform(json) {
return Object.assign(
{},
pick(['name', 'age'], json, null),
buildLinks(flattern(propOr('linkValue', json, [])))
)
}
// EXECUTION
const result = transform(source)
PS> You can use libraries like Lodash or Ramda and replace helper functions defined by me with ones from library

Categories

Resources