Reputation: 273
I have a form model that I am using to map my form fields in AngularJS. Since I am updating these fields on a database I want to retrieve the fields once the user submits the form and comes back to it.
form object:
vm.user = {
userBag:[
{
name: nameService.nameBag[0].organizationName
},
{
name: nameService.nameBag[1].organizationName,
},
{
name: nameService.nameBag[2].organizationName,
}
]
};
I have coded the form object to return the database fields but I'm running into an error when the user initially has nothing submitted in the field bc the object is empty. Getting the error:
"TypeError: Cannot read property 'organizationName' of undefined"
nameServie
is just a get call that retrieves the get.
How do I make it so that the name fields just return a blank if the nameService
is undefined
?
Upvotes: 0
Views: 1308
Reputation: 117
i just met the same problem. googling gave no results, but occasionally i have just solved very similar problem and imagined the following solution:
type Pipeline<T> =
{ [K in keyof T]: Pipeline<T[K]> }
& { VALUE: (defaultValue: T) => T }
export function ppln<T extends {}>(value: T): Pipeline<T> {
function bound(value: any): boolean {
return ["string", "number", "boolean", "undefined", "function"]
.includes(typeof value)
}
return new Proxy<T>(
bound(value) ? {} as T : value, {
get: (_, field: keyof T) => {
if (field === "VALUE") {
return defaultValue => value === undefined ? defaultValue : value
}
if (value && value[field]) {
return ppln(value[field])
}
return ppln(undefined)
}
}) as unknown as Pipeline<T>
}
then it should be possible to do
ppln(obj).prop1[prop2].prop3.VALUE()
ppln(obj).prop1[prop2].prop3.VALUE('default value')
and get either existing value or undefined
without an exception.
second line will produce 'default value'
if requested value is undefined
.
Upvotes: 0
Reputation: 3316
You can use ternary operator to achieve it:
vm.user = {
userBag:[
{
name: (nameService && nameService.nameBag && nameService.nameBag[0]) ? nameService.nameBag[0].organizationName : ""
},
{
name: (nameService && nameService.nameBag && nameService.nameBag[1]) ? nameService.nameBag[1].organizationName : ""
},
{
name: (nameService && nameService.nameBag && nameService.nameBag[2]) ? nameService.nameBag[2].organizationName : "",
}
]
};
Upvotes: 2
Reputation: 3115
There are several ways to accomplish what you want:
Using a ternary operator you could have something like:
vm.user = {
userBag:[
{
name: nameService ? nameService.nameBag[0].organizationName : ''
},
{
name: nameService ? nameService.nameBag[1].organizationName : ''
},
{
name: nameService ? nameService.nameBag[2].organizationName : ''
}
]
};
With the ||
operator you can evaluate if the path you want to access "exists" or has value:
{
name: (nameService && ... && nameService.nameBag[0].organizationName) || ''
}
However in order to keep things DRY I would rather use a function for optional access, something like:
function optionalAccess(obj, path, def) {
const propNames = path.replace(/\]|\)/,'').split(/\.|\[|\(/);
return propNames.reduce((acc, prop) => acc[prop] || def, obj);
}
const obj = {
items: [{ hello: "Hello" }]
};
console.log(optionalAccess(obj, "items[0].hello", "def")); // prints: Hello
console.log(optionalAccess(obj, "items[0].he", "def")); // prints: def
There is currently a proposal in order to be able to use chaining, which would allow you to do something like:
nameService?.nameBag[0]?.organizationName || ''
If you want to do something like that there is also the babel plugin
https://www.npmjs.com/package/babel-plugin-transform-optional-chaining
Upvotes: 0