Map manipulation in Node JS - javascript

As I have 4 key/value in map , I'm trying to store two keys in string format and rest two in an array.
right now what output I'm getting :
{ url: 'account/43',
status: '200',
headers: '\'content-type\' = \'application/json\'',
body: '{ name: Fatma Zaman }' }
Expected output:
{ url: 'account/43',
status: '200',
headers: [ '\'content-type\' = \'application/json\'' ],
body: [ '{ "name": "Fatma Zaman" }' ]}
below are the code which is returning all key/value pair in string, I can make all key/value pair in array but not sure how to do only two key's value to array.
function processFile(content) {
lodash.forEach(content, function(node) {
if (node.startsWith("//")) {
key = node.substring(2, node.length - 2).toLowerCase().trim()
return
} else {
value = node
}
map[key] = value
})
console.log(lodash.map(map, "key"))
return map
}

You can add a simple condition based on key name and put the value in array
map[key] = ['header', 'body'].includes(key) ? [value] : value;
function processFile(content) {
lodash.forEach(content, function(node) {
if (node.startsWith('//')) {
key = node
.substring(2, node.length - 2)
.toLowerCase()
.trim();
return;
} else {
value = node;
}
map[key] = ['header', 'body'].includes(key) ? [value] : value;
});
return map;
}

Related

FormData append deep nested object

Is it possible to append nested object to FormData?
let formData = new FormData();
let data = {
title: 'title',
text: 'text',
preview: {
p_title:'p title',
p_text: 'p text',
files: [
{file: File},
{file: File}
]
}
};
I tried this but this didn't help me:
for ( let dataKey in data ) {
if (dataKey === 'profile_applicant') {
for (let previewKey in data[dataKey]) {
formData.append(`${previewKey}`, data[dataKey][previewKey]);
}
} else {
formData.append(dataKey, data[dataKey]);
}
}
Server console - console.log(req.body):
first_name: test
last_name: test
date_of_birth: test
last_contact: test
files: [object Object],[object Object]
I hope I can help, I did it in a simpler way and I believe it works for all hypotheses, please test.
If it doesn't fit your use case, please comment so I can edit my answer.
Full Code:
const parses = []
const fKey = key => ((function until(value, comp = value) {
const result = value.replace(/\.([A-z0-9]*)(\.|$)/, '[$1]$2')
return comp !== result ? until(result, value) : result
})(key))
function populateFormData(values, form = new FormData(), base = '') {
Object.keys(values).forEach(key => {
const value = values[key]
if (typeof value == 'string' ||
typeof value == 'number' ||
typeof value == 'boolean' ||
value instanceof File ||
value instanceof Blob)
{
form.append(fKey(`${base}${key}`), value)
parses.push({
key: `${fKey(`${base}${key}`)}`,
value
})
}
else if (typeof value == 'object')
{
populateFormData(value, form, `${base}${key}.`)
}
})
return form;
}
populateFormData({
title: 'Lucas',
text: 'Is good :)',
preview: {
p_title: 'I am a P title',
p_text: 'I am a P text',
test: {
example: 2,
my: {
obj: [
'eba',
{
hyper: 'text'
},
123
],
yes: true
}
}
}
})
console.log(parses)
Files are particular objects, you have to append them like this:
files?.forEach(item => { formData.append('files[]', item.originFileObj) })
You should find your originFileObj in your file object, often sending all file can be a problem; It's important too to use [] on the append key, otherwise if files are multiple won't be found.

How can I append the values to the nested keys inside the object in the model through formdata

I have a modal on server side having object like
location: {
lat: {
type: Number
},
lng: {
type: Number
}
},
Now I want to append the values to lat and lng inside the location object. How can I achieve that? I know we can append the values to location like
formData.append("location", value);
I hope I can help, I did it in a simpler way and I believe it works for all hypotheses, please test.
If it doesn't fit your use case, please comment so I can edit my answer.
Full Code:
const parses = []
const fKey = key => ((function until(value, comp = value) {
const result = value.replace(/\.([A-z0-9]*)(\.|$)/, '[$1]$2')
return comp !== result ? until(result, value) : result
})(key))
function populateFormData(values, form = new FormData(), base = '') {
Object.keys(values).forEach(key => {
const value = values[key]
if (typeof value == 'string' ||
typeof value == 'number' ||
typeof value == 'boolean' ||
value instanceof File ||
value instanceof Blob)
{
form.append(fKey(`${base}${key}`), value)
parses.push({
key: `${fKey(`${base}${key}`)}`,
value
})
}
else if (typeof value == 'object')
{
populateFormData(value, form, `${base}${key}.`)
}
})
return form;
}
populateFormData({
title: 'Lucas',
text: 'Is good :)',
preview: {
p_title: 'I am a P title',
p_text: 'I am a P text',
test: {
example: 2,
my: {
obj: [
'eba',
{
hyper: 'text'
},
123
],
yes: true
}
}
}
})
console.log(parses)

Object name from array value

I have array with some values :
let typeArray = ["name", "strret", "car", "type"];
And I have one object :
let formDefinitionObject = {schema:{}}
I want the formDefinitionObject object be like :
let formDefinitionObject = {
schema: {
name: {
type: 'string',
title: 'Name',
required: true
},
strret: {
type: 'string',
title: 'Strret'
},
car: {
type: 'string',
title: 'Car'
},
type: {
type: 'string',
title: 'Type'
}
}
}
I want dynamically for each item in array to be object in formDefinitionObject.schema object. For example if i add one more item in array typeArray.push('country') to automatic add this object in formDefinitionObject.schema object.
Couldn't understand how required: true would fit in. Remaining things can be done as follows
var getFormDefinition = function(arr) {
function getSchemaObj(arr) {
return arr.map(d => ({
[d]: {
type: typeof(d),
title: d
}
}))
.reduce((a, b) => ({ ...a, ...b }))
}
var schemaObj = getSchemaObj(arr)
arr.push = function(...d) {
Object.assign(schemaObj, getSchemaObj(d))
return Array.prototype.push.call(arr, ...d)
}
return ({
schema: schemaObj
})
}
var typeArray = ["name", "strret", "car", "type"];
var result = getFormDefinition(typeArray)
console.log(result)
typeArray.push('nitish')
console.log(result)
Even though you did not clarify more how a field has to be required or does any field has to be as string, here's a solution based on what you provided so far.
The next snippet does the job and it has some explanations :
let typeArray = ['name', 'strret', 'car', 'type'],
formDefinitionObject = {
schema: {}
};
/** cycle through "typeArray" and populate "formDefinitionObject.schema" **/
typeArray.forEach(el => {
let currObj = {
type: 'string', /** YOU DID NOT SPECIY HOW TO DECIDE THE TYPE **/
title: el[0].toUpperCase() + el.substring(1), /** the title with the first letter being capitalized as you provided in the question. You can just use "el" instead of "el[0].toUpperCase() + el.substring(1)" if you'd like to print as it is **/
};
el === 'name' && (currObj['required'] = true); /** YOU DID NOT SPECIY HOW TO DECIDE IF A FIELD HAS TO BE REQUIRED. I just saw only the "name" as required so I did a basic (yet a stupid) check if the current element is "name" add a required to it **/
formDefinitionObject.schema[el] = currObj; /** add the current record to the "schema" attribute **/
});
console.dir(formDefinitionObject); /** printing the result **/
I'll be here if you answer our questions in the comments section.
Til then, hope I pushed you further.
You could use Proxy on the typeArray with the set trap so each time you push new value to the proxy array you can also add new property to your schema. This way you can simulate observer pattern.
You can also create some pattern to add additional properties like required for example name:prop1:prop2 but this way value is fixed to true.
let typeArray = ["name:required", "strret", "car", "type"];
let formDefinitionObject = {
schema: {}
}
let proxyArray = new Proxy(typeArray, {
set(obj, prop, value) {
if (prop != 'length') addToSchema(formDefinitionObject.schema, value);
return Reflect.set(...arguments);
}
})
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function addToSchema(schema, prop) {
const [name, ...params] = prop.split(':');
schema[name] = {
type: 'string',
title: capitalize(name)
}
params.forEach(param => schema[name][param] = true);
return schema;
}
proxyArray.reduce(addToSchema, formDefinitionObject.schema);
proxyArray.push('email:required:isEmail');
proxyArray.push('phone');
console.log(formDefinitionObject)
Update: You could use something like this name:prop1|value:prop2 to add property value other then true but if you don't specify value default is still true
let typeArray = ["name:required", "strret", "car", "type"];
let formDefinitionObject = {
schema: {}
}
let proxyArray = new Proxy(typeArray, {
set(obj, prop, value) {
if (prop != 'length') addToSchema(formDefinitionObject.schema, value);
return Reflect.set(...arguments);
}
})
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function addToSchema(schema, prop) {
const [name, ...params] = prop.split(':');
schema[name] = {
type: 'string',
title: capitalize(name)
}
params.forEach(param => {
const [key, value] = param.split('|');
schema[name][key] = value ? value : true
});
return schema;
}
proxyArray.reduce(addToSchema, formDefinitionObject.schema);
proxyArray.push('email:required:isEmail');
proxyArray.push('phone:default|123/555-333:required');
proxyArray.push('address')
console.log(formDefinitionObject)

TypeError: map[key].push is not a function

I'm not sure why I'm getting this error as I do have map variable declare in my function:-(
if I run below code :
if (key in map) {
map[key].push(value)
} else {
map[key] = value
}
my output would be like this :
{ url: ['account/43' ],
status: [ '200' ],
headers:
[ 'content-type = application/json',
'content-type = application/text' ],
body: [ '{ name: xyz}' ] }
Instead of that if I run below line of code inside the function :
map[key] = ["headers", "body"].includes(key)? [value] : value
the output would be like below( url/status in string and headers/body in array format) but its not taking multiple value of headers, basically it's replacing the value.
{ url: 'account/43',
status: '200',
headers: [ 'content-type = application/text' ],
body: [ '{ name: xyz }' ] }
I'm trying to achieve kind of both condition( firstly , url.status should be in string format and headers/body should be in array format. secondly headers or body can append/push multiple value like below output:
{url: 'account/43',
status: '200',
headers:
[ 'content-type = application/json',
'content-type = application/text' ],
body: [ '{ name: xyz }' ] }
Here is the actual function
function processFile(content) {
let map = {}
content.forEach(function(node) {
if (node.startsWith("//")) {
key = node.substring(2, node.length-2).toLowerCase().trim()
return
} else {
value = node
}
if (key in map) {
map[key].push(value)
} else {
map[key] = value
}
map[key] = ["headers", "body"].includes(key)? [value] : value
})
return map
}
ERROR
map[key].push(value)
^
TypeError: map[key].push is not a function
This is how you can do it -
function processFile(content) {
let map = {}
content.forEach(function(node) {
if (node.startsWith("//")) {
key = node.substring(2, node.length - 2).toLowerCase().trim()
return
} else {
value = node
}
if (key in map) {
map[key].push(value)
} else {
map[key] = [value];
}
map[key] = ["headers", "body"].includes(key) ? [value] : value
})
return map
}
You've ensured that for headers and body, multiple values are possible. However, based on the error, it's evident that there is a duplicate for some other key as well.
Consider using a function like this:
function processFile(content) {
let key;
return content.reduce(
function (map, node) {
if (node.startsWith('//')) {
key = node.substring(2, node.length-2).toLowerCase().trim();
} else if (key) {
if (map[key]) {
if (map[key].push) {
map[key].push(node);
} else {
throw new Error(`Duplicate key ${key} for scalar value`);
}
} else {
map[key] = node;
}
} else {
throw new Error(`Data encountered without a key: ${node}`);
}
return map;
},
{ headers: [], body: [] }
);
}
This will throw an error when the duplicate key is encountered, giving you a chance to debug it.
Other improvements I made:
Use reduce() instead of forEach().
Initialize the map with an empty array for headers and body, which eliminates the need for a special-case test in your iteration function.
Declared key, which was previously unnecessarily a global.
Data without a previously-seen key causes an error instead of storing the data at map["undefined"].
The method push() belongs to the Array class.
When you do:
map[key] = value
and latter call:
map[key].push(value)
There was no array in map[key]. In order to push an element here we need to store an array in map[key]. To do so, instead of
map[key] = value //element value being stored in map[key]
we need to do something like this:
map[key] = [value] // array containing value in the first position
Initializing and storing the array.

Why is the following map function returning the strings with commas?

I'm looping through an object. If one of its keys matches the value of another fields object then return the value of type of that fields object:
// OBJECTS
user: {
email: '',
password: ''
}
formFields: [
{ name: 'email', type: 'text', required: true },
{ name: 'password', type: 'password', required: true }
]
// HTML
<input :type="getPropType($key)"
// FUNCTION
getPropType (key) {
console.log(this.fields)
console.log(key)
return this.fields.map(field => {
if (field.name === key) return field.type
})
}
It works except a comma is returned with every field.type:
Which is strange since the logs don't output any commas:
What could be the cause?
I think what you are trying to do is to extract the type of the object with the same name as the value of key, in that case a more appropriate solution will be to do that exactly that - ie find the element with the given name then extract its type
getPropType(key) {
console.log(this.fields)
console.log(key);
var type;
this.fields.some(field => {
if (field.name === key) {
type = field.type;
return true;
}
});
return type
}
If you want to use .map(), then
return this.fields.filter(field => field.name === key).map(field => field.type).join('')
Array.prototype.map() returns array. Your "getPropType" returned ["text", ""] and it should be reduced in your case.
return this.fields.map(field => {
if (field.name === key) return field.type
}).reduce(function(prev, curr, index, array){return prev + curr});

Categories