I'm building a node+express app and I'm filling an object with JSON that's submitted from a form in the frontend. This works, unless I leave a field empty in the form so that e.g. req.body.address.street is empty/undefined.
This will result in the error:
TypeError: Cannot read property 'street' of undefined
var b = new Business({
name: req.body.name,
phone: req.body.phone,
address: {
street: req.body.address.street,
postalCode: req.body.address.postalCode,
city: req.body.address.city
},
owner: {
email: req.body.owner.email,
password: req.body.owner.password
}
});
My question is how I can best prevent my app from crashing when values are empty. I would like to avoid manually checking each and every property in my app against undefined.
I'm wondering what the best practice is for this common issue.
I don't know if you use jQuery in your project, but if you do, you can create a mask:
// creating your object mask
var req = {
body: {
name: '',
phone: '',
address: {
street: '',
postalCode: '',
city: ''
},
owner: {
email: '',
password: ''
}
}
}
And then, you simply use the jQuery "extend" method (req2 is your submmited object):
$.extend(true, req, req2);
I've create this fiddle for you!
-
Update
Nothing related to your question, but I've just noticed that you're passing an object with a similar structure of req.body to the Business class. However, there is no need to copy property by property manually - you can make, for example, a simple copy of req.body to pass as parameter:
var b = new Business($.extend({}, req.body));
or
var b = new Business(JSON.parse(JSON.stringify(req.body)));
You can't, really. You have two options;
Use a try/ catch:
try {
var b = new Business({
//
});
} catch (e) {
// Something wasn't provided.
}
... or you can define a helper function:
function get(path, obj) {
path = path.split('.');
path.shift(); // Remove "req".
while (path.length && obj.hasOwnProperty(path[0])) {
obj = obj[path.shift()];
}
return !path.length ? obj : null;
}
... you could then replace your use of req.body.address.street etc. with get('req.body.address.street', req).
See a demo here; http://jsfiddle.net/W8YaB/
Related
I have the following object to which I wish to have a conditional property:
{ name: this.username, DOB: new Date(this.inputDate)}
Say, I wish to add a third property called gender if the user has specified their gender. What would the proper syntax for the following be:
{ name: this.username, DOB: new Date(this.inputDate), if(this.userGender) gender: this.userGender}
P.S. I do not wish to have the gender property in my object if there is no value along with it. So how can I only create the property if the condition is satisfied?
Ideally, you would just add the appropriate property as a second action after declaring your object. So something like:
const myObj = {
name: this.username,
DOB: new Date(this.inputDate),
}
if(this.userGender) myObj.gender = this.userGender;
However, sometimes it's nice to declare an "optional" property inline with the rest of them, in which case you can use object spread to get the effect you're looking for:
const myObj = {
name: this.username,
DOB: new Date(this.inputDate),
...this.userGender
? { gender: this.userGender }
: {}
}
it can be done like this too, more clean and readable.
const myObj = {
name: this.username,
DOB: new Date(this.inputDate),
...(this.userGender && { gender : this.userGender })
}
Try this
let userObj = { name: this.username, DOB: new Date(this.inputDate) }
if(this.userGender)
userObj[:gender] = this.userGender;
Hi Im still learning node and trying something cool with javascript nodejs.
Meanwhile I got stuck when pass separate "where" sequelize statement into one.
Okay, this is my current code :
var periodsParam = {};
periodsParam = {
delete: 'F',
tipe: 1,
variantid: (!ctx.params.id ? ctx.params.id : variants.id)
};
if (ctx.query.country) {
periodsParam = {
country: ctx.query.country
};
}
console.log(periodsParam);
From code above, its always return { country: 'SG' } , but I want to return { delete: 'F', tipe: 1, variantid: 1, country: 'SG' }
How can I resolve that ?
Anyhelp will appreciate, thankyouu.
The problem is, you're using = sign with periodsParam 3 times and you end up with periodsParam returning only country, because of this lines:
if (ctx.query.country) {
periodsParam = {
country: ctx.query.country
};
}
Instead of assigning new object to periodsParam, use dot notation to add another key-value pair, like this:
if (ctx.query && ctx.query.country) { //before accesing .country check if ctx.query is truthy
periodsParam.country = ctx.query.country;
}
As #Paul suggested, condition should be ctx.query && ctx.query.country - it will prevent TypeError if ctx.query is undefined.
The problem was that you were always re initializing it. You should set it as a property of the existing object.
Update from
periodsParam = {
country: ctx.query.country
};
to
periodsParam.country = ctx.query.country;
You can also just assign the Object like this:
periodsParam = Object.assign({}, periodsParam, { country: ctx.query.country });
Im working on a profile editing page in an ionic app everything works as fine with all the top level items of the users profiles info (name, email, sex etc..)
I have hobbies stored in an array off this main json node (using Firestore) so its 1 level deep off the main node..
I cant seem to figure out how to use form builder with it. I suspect I am going wrong on 2 points, 1 being how I am using formbuilder and 2 on the merge fuction as it doesnt take into account nested structures which I am also unsure how to approach.. any help would be awesome.
_buildForm() {
this.form = this.formBuilder.group({
displayName: [this.options.displayName] || '',
dob: [this.options.dob] || '',
sex: [this.options.sex] || '',
city: [this.options.city] || '',
country: [this.options.country] || '',
bio: [this.options.bio] || '',
hobbies: this.formBuilder.group( this.options.hobbies )
});
// Watch the form for changes, and
this.form.valueChanges.subscribe((v) => {
this.merge(this.form.value);
});
}
merge(settings: any) {
for (let k in settings) {
this.settings[k] = settings[k];
}
return this._save();
}
_save() {
// this function then save the data back to firestore using a simple update of the entire json output
}
You need these
_buildForm() {
this.form = this.formBuilder.group({
displayName: [this.options.displayName] || '',
dob: [this.options.dob] || '',
sex: [this.options.sex] || '',
city: [this.options.city] || '',
country: [this.options.country] || '',
bio: [this.options.bio] || '',
hobbies: this.formBuilder.group([])
});
if(this.options.hobbies.length>0){
this._setHobbiesForm(this.options.hobbies);
}
}
//To build the hobby gorm
_buildHobbyForm(hobby) {
var hobbyForm = this.fb.group({
Name: hobby.Name||''
});
return hobbyForm ;
}
//To attach the hobbies form with data back to main form
_setHobbiesForm(hobbies) {
const hobbiesFGs = hobbies.map(hobby=> this._buildHobbyForm(hobby));
const hobbiesFR = this.fb.array(hobbiesFGs);
this.form.setControl('hobbies', hobbiesFR);
}
//To get form values for saving
_prepareSaveInfo(){
const formModel = this.form.value;
//deep copy of hobbies
const hobbiesDeepCopy= formModel.hobbies.map(
(hobby) => Object.assign({}, hobby)
);
const profile={
displayName: formModel.displayName as string,
sex: formModel.sex as string,
dob: formModel.dob as string,
city: formModel.city as string,
country: formModel.country as string,
hobbies:hobbiesDeepCopy
}
return profile;
}
_save() {
let dataToSave=this._prepareSaveInfo();
console.log(dataToSave);
}
This is the way to handle array inside forms in angular , if it doesn't fits your code logic exactly , take it as a example and build your logic from it , definitely this example will help you .
Iam posting an example for html also here (basically to show how to handle arrays inside the form in html)
<div formArrayName="hobbies">
<div *ngFor="let hobby of form.get('hobbies').controls; let i=index" [formGroupName]="i">
<!-- your code for hobby-->
</div>
</div>
I want to edit a existing user in Node. My front-end is in pug.
My user table has lots of fields (about 20 to 25), and some have to be unique, like email and username, which I have functions to check if they are not a duplicate.
I only want to update values that has changed on the client, my edit form already has the values of the user of course.
I thought the best way to achieve this is to check all the inputs from req.body, and if it is different from any user values, I should update it. (Perhaps any different methods? Can't I check if the inputs are 'dirty'?)
This could be the situation. Note the req.body object, with values that my user table doesn't have, like password_confirm
req.body = {
username: 'test',
email: 'user#user.com',
password: '1234',
password_confirm: '1234',
location: 'New York',
website: 'new-website.com',
bio: undefined,
expertise: 'New expertise'
}
user = {
username: 'test',
email: 'user#user.com',
password: '1234',
location: 'San Fransico',
website: 'website.com',
bio: null,
expertise: null
}
I now only want to update the changed location, website and expertise fields. I tried many things, using reduce and lodash, but I can't get the fields that I'm looking for.
NB
I already checked different StackOverflow questions but nothing seems to work for my situation..
From what I understood from your question, give this a try,
Object.keys(req.body).forEach((key)=>{
if(user[key] && user[key]!=req.body[key]){
user[key] = req.body[key];
}
})
Well, I think you are over complicating. You don't even need lodash for this.
Object.assign({}, user, req.body);
would work, since you said yourself that you can have different fields in req.body.
If you need diff object use this:
function diff(oldObject, newObject) {
const diff = {};
Object.keys(oldObject).forEach((key) => {
if (oldObject[key] != newObject[key] && newObject[key] !== undefined) {
diff[key] = newObject[key];
}
});
return diff;
}
var body = {
username : 'test',
email : 'user#user.com',
password : '1234',
password_confirm : '1234',
location : 'New York',
website : 'new-website.com',
bio : undefined,
expertise : 'New expertise'
}
var user = {
username : 'test',
email : 'user#user.com',
password : '1234',
location : 'San Fransico',
website : 'website.com',
bio : null,
expertise : null
}
function diff(oldObject, newObject) {
const diff = {};
Object.keys(oldObject).forEach((key) => {
if (oldObject[key] != newObject[key] && newObject[key] !== undefined) {
diff[key] = newObject[key];
}
});
return diff;
}
console.log(diff(user, body));
I figured it out.
Based on #ponary-kostek & #anuragasaurus 's answer, this is what worked for me:
const differences = {};
Object.keys(req.body).forEach((key)=> {
if(req.body[key].length == 0) req.body[key] = null;
if(stakeholder.hasOwnProperty(key) && stakeholder[key]!=req.body[key]){
differences[key] = req.body[key];
}
});
This returns an object with the changed keys and their values.
Because the fields from my user object are retrieved from a SQL DB, they are null. Also, empty body fields are not undefined, but strings. Meaning if the input is empty, it is an empty string, and to compare it to my user object it should first be null.
Thanks everyone for their answers.
This question already has answers here:
Convert a JavaScript string in dot notation into an object reference
(34 answers)
Closed 6 years ago.
Context: I'm writing a Redux reducer (although this question is not Redux-specific) for my app's settings, which is a nested object. I want to modify the settings object using property names that are given dynamically.
Example:
const settings = {
service: {
username: 'TEST',
password: ''
}
}
// Normally this would be passed by Redux, but for the purposes of this exercise it's hardcoded
const settingKey = 'service.username';
console.log(settings[settingKey]); // undefined
console.log(eval(`settings.${settingKey}`)); // works, but bad
The only way I can think of accessing the subobject without using eval is using a regex to split the settingKey into its component parts:
const match = /(.+)\.(.+)/.exec(settingKey);
console.log(settings[match[1]][match[2]];
const settings = {
service: {
username: 'TEST',
password: ''
}
}
const settingKey = 'service.username';
const match = /(.+)\.(.+)/.exec(settingKey);
console.log(settings[match[1]][match[2]]);
This works, but
It's ugly
It doesn't work for more deeply nested objects
Is there a way of accessing a nested object's properties with a dynamic name without using regexes or eval?
You can do something like this,
var settings = {service: {username: 'TEST', password: ''}}
var key = "service.username";
function getValue(obj, keys){
keys.split(".").forEach(function(itm){
obj = obj[itm];
});
return obj;
}
getValue(settings, key); //"TEST"
Or you can do it simply using Array#reduce,
var settings = {service: {username: 'TEST', password: ''}}
var key = "service.username", result = key.split(".").reduce((a,b) => a[b], settings);
console.log(result); // "TEST"
Another option that doesn't use eval and works with nested properties.
var settings = {service: {username: 'TEST', password: ''}}
var key = "service.username";
console.log(Function('setting', 'return settings.' + key)(settings));
I think you just change one bit:
const settings = {
service: {
username: 'TEST',
password: ''
}
}
console.log(settings['service'].username);