Getting error: Cannot read properties of undefined in javascript - javascript

While calling function getting error:
Uncaught TypeError: Cannot read properties of undefined (reading 'username')
at getLoginData (<anonymous>:3:30)
at <anonymous>:1:1"
role1 has value "administrator", but why it is not able to call in datamodel? (Datamodel here refers is another JSON file)
datamodel = {
administrator: [
{
username: "abc#xyz.com",
password: "abc#1234",
},
{
username: "abcd#xyz.com",
password: "xyz#1234",
},
],
};
function getLoginData(role1) {
console.log(role1);
let name = datamodel.role1.username;
}
getLoginData("administrator[0]");

You can't access object in that was, the code thinks that role1 is a key in that Object.
function getLoginData(role1){
console.log(role1)
let name=datamodel[role1][0].username
}
getLoginData("administrator")

var datamodel = {
"administrator": [
{
"username": "abc#io.com",
"password": "abc#1234"
},
{
"username": "xyz#io.com",
"password": "xyz#1234"
}
]
}
console.log(datamodel);
var name = datamodel.administrator[0].username; //get the name of administrator[0] = "rinty.kurian#espacenetworks.io"
console.log(name);
Try this :)

First of all you need to use Brackets Notation to access an object's attribute that is stored inside of another variable. So assuming you want the first credentials from the administrators array you would write something like datamodel.administrator[0].
Since, as it seems from your function's call, getLoginData('administrator[0]'), you would like that the function getLoginData to take care of accessing the inner administrators array which we cannot directly using brackets notation as datamodel['administrators[0]'] will raise an error because the attribute "administrators[0]" (string) doesn't exist in the datamodel object.
What we need to do is to try to extract the index of the items we want to return, if it exists, and then use that to return the right credentials from the datamodel object.
To do so, we will split the argument that is passed to getLoginData to get the attribute we want to access (ex: administrators) and the index (ex: 0).
Here's a live demo to implement such functionality:
const dataModel = {
"administrator": [{
"username": "abc#xyz.com",
"password": "abc#1234"
},
{
"username": "abcd#xyz.com",
"password": "xyz#1234"
}
]
},
/**
* a function that accepts an attribute name and optional index to get from "datamodel" object
*/
getLoginData = role => {
/**
* split the role parameter to get the wanted index if there is one
* the trick here is that we will replace the brackets around the index with a space and only keep the index itself (we'll get rid of those brackets)
* we should make some checks to prevent undefined index like errors
*/
const splitted = role.replace(/\[(\d+)\]/, ' $1').split(' '),
attr = dataModel[splitted[0]] ? (splitted.length > 1 ? dataModel[splitted[0]][splitted[1]] : dataModel[splitted[0]]) : null;
/** return the appropriete attribute or null if not defined */
return attr ? attr.username : null;
};
// prints: "abc#xyz.com"
console.log(getLoginData("administrator[0]"))
UPDATE
Here's another possible solution that works by passing the item index as the second parameter to datamodel object.
const dataModel = {
"administrator": [{
"username": "abc#xyz.com",
"password": "abc#1234"
},
{
"username": "abcd#xyz.com",
"password": "xyz#1234"
}
]
},
/**
* a function that accepts an attribute name and an index to get from "datamodel" object
*/
getLoginData = (role, index) => dataModel[role] && dataModel[role][index] ? dataModel[role][index].username : null;
// prints: "abc#xyz.com"
console.log(getLoginData("administrator", 0))

Related

How to change nested JSON value using stringify replacer?

I use JSON.stringify(value, replacer) to mask sensitive data in JSON object.
const inputJsonObject =
{
"id": "uniqueId",
"value": "objectData",
"user": {
"password": "qwerty"
}
};
const hideDataMethod = JSON.stringify(inputJsonObject, (key, value) => {
const dataToHide = ['id', 'user.password'];
return dataToHide.indexOf(key) === -1 ? value : 'xxx';
});
console.log(hideDataMethod);
How to get to user.password value? The above solution works for id but doesn't for password.
It doesn't work for password because you're looking for a property called "user.password", but there is none; the property's name is password, not user.password. (It's a property on an object that's referenced by the user property on another object, but that has nothing to do with the property name.) If you remove the user. part of that, it will work. Beware that doing it removes all id and password properties from all objects in the object graph being stringified:
const inputObject = {
"id": "uniqueId",
"value": "objectData",
"user": {
"password": "qwerty"
}
};
const dataToHide = ["id", "password"];
const json = JSON.stringify(inputObject, (key, value) => {
return dataToHide.indexOf(key) === -1 ? value : "xxx";
});
console.log(json);
(I also changed the name of a couple of variables that had misleading names.)
But I would sanitize it before converting it to JSON rather than during:
const tmp = {
...inputObject,
id: "xxx",
user: {
...inputObject.user,
password: "xxx",
}
};
const json = JSON.stringify(tmp);

Deleting json value with javascript

I have tried to many ways , but i am stuck with a simple function in javascript, and i don't know where i need to looking for ... the problem is this:
I have a Json file like this one:
{
"blacklist": [
{
"email": "strangemail#gmail.com"
},
{
"email": "strangemail1#gmail.com"
},
{
"email": "strangemail2#gmail.com"
},
{
"email": "fianlt#gmail.com"
},
{
"email": "finalstatustest#gmail.com"
}
]
}
I would like simple remove an email with a simple function like this one:
function cancel(email) // parameter that contain the value to delete
{
let rawdata = fs.readFileSync('pvt.json'); //get local json file
let mydata = JSON.parse(rawdata); //parsing rawdata
var key = email; //setting up key
delete mydata.blacklist[key]; //using delete function for delete an element
let data = JSON.stringify(mydata, null, 2); //stringify the result
fs.writeFileSync('pvt.json', data); // overwrite local file with new one with all changes
}
the problem is ... it doesn't works ... i don't know why ... i tried to read the documentation, but i didn't found any solution 😢
The delete operator is for removing a property from an object, using the property's name. You're trying to remove an entry from an array, using the value of a property of an object in the array.
Assuming email is a variable containing the email address in the entry you want to remove, filter is one easy way to do that:
mydata.blacklist = mydata.blacklist.filter(entry => entry.email !== email);
filter builds a new array from the entries in the original array that meet the criteria in the callback — in this case, that their email property doesn't match the email address you want to remove.
If you wanted to modify the array in place rather than creating a new one, you'd use findIndex and splice:
const index = mydata.blacklist.findIndex(entry => entry.email === email);
if (index !== -1) {
mydata.blacklist.splice(index, 1); // Remove the entry at the index
}
Delete works to delete a key-value from an object. Here you have an array of items[objects]. You should use filter to remove unwanted element.
Update:
function cancel(selectedEmail) {
let rawdata = fs.readFileSync("pvt.json"); //get local json file
let mydata = JSON.parse(rawdata); //parsing rawdata
mydata.blacklist = mydata.blacklist.filter(
(item) => item.email !== selectedEmail.email
);
fs.writeFileSync("pvt.json", JSON.stringify(mydata, null, 2)); // overwrite local file with new one with all changes
}
Sample:
const info = {
blacklist: [
{
email: "strangemail#gmail.com",
},
{
email: "strangemail1#gmail.com",
},
{
email: "strangemail2#gmail.com",
},
{
email: "fianlt#gmail.com",
},
{
email: "finalstatustest#gmail.com",
},
],
};
const selectedEmail = {email: "finalstatustest#gmail.com"}
info.blacklist = info.blacklist.filter(item => item.email !== selectedEmail.email)
console.log(info)

How to update multiple fields of an array object with one request?

{
_id:xxxxstoreid
store:{
products:[
{
_id:xxxproductid,
name:xxx,
img:url,
}
]
}
}
since i cannot predict the request for update, params may have just name or it may have both.
here is my query,it updates successfully but it removes other fields if they are not present in the params.
eg:
var params={_id:xxid,name:'xxx',img:'xxx'}
or
var params={_id:xxid,name:'xxx'}
in this case if params have just name it removes img field and updates.
User.update({'store.products._id':params._id},{$set:{"store.products":params}},callback);
You need to supply the multiple keys to $set with the positional $ operator to update both matched keys.
I prefer the modern ES6 way of object manipulation:
let params = { "_id" : "xxxproductid", "name" : "xxx", "img" : "yyy" };
let update = [
{ 'store.products._id': params._id },
{ "$set": Object.keys(params).filter(k => k != '_id')
.reduce((acc,curr) =>
Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
{ })
}
];
User.update(...update,callback);
Which would produce the call to MongoDB as ( with mongoose.set('debug', true) ) turned on so we see the request:
Mongoose: users.update({ 'store.products._id': 'xxxproductid' }, { '$set': { 'store.products.$.name': 'xxx', 'store.products.$.img': 'yyy' } }, {})
Where basically you take your input params and supply the _id as the first argument for the "query" :
{ 'store.products._id': params._id },
The rest takes the "keys" from the object via Object.keys which makes an "array" which we can "filter" with Array.filter() and then pass to Array.reduce to transform those keys into an Object.
Inside the .reduce() we call Object.assign() which "merges" objects with the given keys, generated in this form:
Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
Using the template syntax to assign the "current" (curr) "key" into the new key name, again using the ES6 key assignment syntax []: which allows variable names in object literals.
The resulting "merged" object is passed back to be assigned to the "root" object where $set is used for the key of the update, so the "generated" keys are now children of that.
I use an array for the arguments purely for debugging purposes, but then that also allows cleaner syntax on the actual .update() using the "spread" ... operator to assign the arguments:
User.update(...update,callback);
Clean and simple, and some JavaScript techniques that you should learn for object and array manipulation. Mostly since the MongoDB query DSL is basically "Objects" and "Arrays". So learn to manipulate them.
function updateProducts(params) {
var query = {'store.products': {$elemMatch: {_id: params._id}}}
var updateObject = null;
if (params.name && params.img) {
updateObject = {$set: {'store.products.$': params}}
} else if(params.name && !params.img) {
updateObject = {$set: {'store.products.$.name': params.name}}
} else if (params.img && !params.name) {
updateObject = {$set: {'store.products.$.img': params.img}}
}
User.update(query, updateObject, callback)
}
The below query will use $ positional operator to locate the array element at index found from matching the array by _id in the query document followed by updating the fields for the element with the params values.
var params = {_id:1, name:'xxx',img:'yyy'};
var id = params['_id']; // Get id to locate matching array index
delete params['_id']; // Remove id from the object
Object.keys(params).forEach(function (key){params['store.products.$.'+key] = params[key]; delete params[key];}) // Transforms remaining object keys to include the positional $ placeholder to { "store.products.$.name" : "xxx", "store.products.$.img" : "yyy" }
User.update('store.products._id':id},{$set:params},callback);

How to insert json values into object

I have a predefined object (SampleObject) like this:
{
ID: "",
Name: "",
URL: "",
prevName: "",
Code: "",
}
And I want to insert the below json object values(values only):
var object =
{
"Sample" : {
"Data" : {
"ID" : "12345",
"Name" : "SampleName: Name",
"URL" : "www.google.com",
"prevName" : "phones",
"Code" : "USD"
}
}
into the above predefined object. How do I do that?
You can just use a for in loop and set the value checking if the key is present in the object or not.
Check if the property is present on the emptyObject, and then copy that over to it.
for (var key in pageInfo) {
var value = pageInfo[key];
if (obj.hasOwnProperty(key)) {
obj[key] = value;
}
}
Code Pen
It is an object. There is no reason to use push or another method.
Simply take your defined object pageObject.page and assign a new key value pair with literal syntax.
pageObject.page['pageInfo'] = predefinedObject
or in more common syntax
pageObject.page.pageInfo = predefinedObject
Use the following code below the JSON Object
var digitalData= {page:{pageInfo:''}};
digitalData.page.pageInfo = pageObject.page.pageInfo;
console.log(digitalData.page.pageInfo);

Create a empty JSON object from an existing JSON object array

I have a JSON object with two arrays of an object x.
I'm using angularJS and I want to add/edit/delete objects in the JSON (just like the Angular TODO app example on angular.org).
Is there a way to create a new empty (with the structure of x but no values) JSON object of x, and simply push that to the above JSON object array?
How do I go about creating an empty value JSON object of x?
My Sample object x is (I nullified all the values) pasted below. So my JSON is just an array of these objects. In Angular, I want the user to fill out a form and hold the data in an empty object of this type and push it to the array. That's my goal.
Sample JSON
[{
"id": null,
"title": "",
"date": {},
"billPayerId": null,
"notes": "Sample Notes",
"billFinances": {
"billPayerId": null,
"billItemEntry": [
{
"itemDescriptionId": 1,
"itemDescription": "",
"userIdAndLiableCost": [
{
"userId": null,
"liableCost": null
},
{
"userId": null,
"liableCost": null
}
]
},
{
"itemDescriptionId": null,
"itemDescription": "",
"userIdAndLiableCost": [
{
"userId": null,
"liableCost": null
},
{
"userId": null,
"liableCost": null
}
]
}
],
"billTotal": null
},
"groupId": null
}];
You can use an object literal to store whatever you want. It is just a bag of properties (i.e. name) and values. e.g. var order = {};
Then an array literal could be used to hold the orders. e.g var orders = []; orders.push(order); But it would be just as easy to use another object literal with the id as a property.
But it seems like you want some sort of validation. Perhaps something to manage the order data and handle the validation, etc. Like so:
orderManager.dataStore = {
_data: {},
//_redundantData = []; //could easily store in an array if id isn't unique
get: function (id) {
return this._data[id];
},
getAll: function () {
return this._data;
},
set: function (id, order) {
validateOrder(order);
this._data[id] = order;
},
clear: function (id) {
this._data[id] = undefined;
},
add: function (order) {
validateOrder(order);
this._data[order.id] = order;
},
assertNotNull: function (data, key) {
if(data[key] == undefined) {
throw new Error("Key Missing: " + key + " for " + data.name);
}
},
validateOrder: function(order) {
assertNotNull(order,"id");
assertNotNull(order,"title");
//etc
},
containsOrder: function (id) {
for(var i=0;i<array.length;i++) {
if(array[i].id === id) {
return true;
}
}
return false;
}
};
If I'm reading all of this right, I think you may be misunderstanding how Angular works. You don't have to create an empty object for Angular to use within a form. As long as your form's inputs use dot notation, it will generate the object for you as the user fills in the inputs with data.
E.g.
<form>
<input type="text" ng-model="myForm.name">
<input type="text" ng-model="myForm.email">
<input type="text" ng-model="myForm.nickname">
</form>
Since we used the dot notation in the ng-model attribute, it creates the object for us as the user fills out the form. The generated object would look like this after the inputs are completed:
$scope.myForm = {
name: 'Justin',
email: 'justin#email.com',
nickname: 'Cerebrl'
};
Now, normally once the user clicks save, you'd send the data to the server for persistence and you could then just empty the object (e.g. $scope.myForm = {};) to reset the form. But, for some reason, you want to build an array first, then send the whole thing to the server when fully complete (at least that's how I'm understanding it).
To do this, you have to get around the fact that Objects and Arrays in JavaScript are reference types, so you can't push the object full of data to an array, and then empty the object to reset the form as that would then empty the object within the array as well, blowing your data store.
I would personally address this problem with Angular's object copy method (e.g. angular.copy(source);) seen here: http://docs.angularjs.org/api/angular.copy This allows you to make a non-referenced copy of an object and use it without mutating the original object. So, within the "save function", you would have this:
var myNewObj = angular.copy($scope.myForm);
myDataArray.push(myNewObj);
$scope.myForm = {};
That way, you've saved the completed form data, pushed it to the array and cleared the form's input data. Does this answer your question?

Categories