Cannot Populate Javascript Object Properties with Values Using Function - javascript

I have the following Javascript object defined:
var APIUserItem = function () {
var
id = '',
account_id = '',
client_id = '',
user_name = '',
salutation = '',
first_name = '',
middle_name = '',
last_name = '',
organization_name = '',
alternate_email = '',
time_zone_id = '',
utcoffset = '',
date_created = new Date(),
last_updated_date = new Date(),
is_active = null,
is_approved = null,
classes = [],
groups = [],
permissions = [],
properties = {},
version_stamp_hash_string = '',
getFromData = function (data) {
id = data.ID;
account_id = data.AccountID;
client_id = data.ClientID;
user_name = data.UserName;
salutation = data.Salutation;
first_name = data.FirstName;
middle_name = data.MiddleName;
last_name = data.LastName;
organization_name = data.OrganizationName;
alternate_email = data.AlternateEmail;
time_zone_id = data.TimeZoneID;
utcoffset = data.UTCOffset;
date_created = data.DateCreated;
last_updated_date = data.LastUpdatedDate;
is_active = data.IsActive;
is_approved = data.IsApproved;
properties = data.Properties;
version_stamp_hash_string = data.VersionStampHashString;
// list of pointers to classes
$.each(data.Classes, function (index, value) {
class_pointer = new APIPointerItem();
class_pointer.ID = value.ID;
class_pointer.PublicID = value.PublicID;
class_pointer.Name = value.Name;
class_pointer.RelativeURI = value.RelativeURI;
classes.push(class_pointer);
});
// list of pointers to Groups
$.each(data.Groups, function (index, value) {
group_pointer = new APIPointerItem();
group_pointer.ID = value.ID;
group_pointer.PublicID = value.PublicID;
group_pointer.Name = value.Name;
group_pointer.RelativeURI = value.RelativeURI;
groups.push(group_pointer);
});
// list of permissions
$.each(data.Permissions, function (index, value) {
permission_pointer = new APIPermissionList();
permission_pointer.ID = value.ID;
permission_pointer.Description = value.Description;
permission_pointer.Category = value.Category;
permission_pointer.Level = value.Level;
permission_pointer.ResourceType = value.ResourceType,
permission_pointer.Action = value.Action;
permissions.push(permission_pointer);
});
};
return {
ID: id,
AccountID: account_id,
ClientID: client_id,
UserName: user_name,
Salutation: salutation,
FirstName: first_name,
MiddleName: middle_name,
LastName: last_name,
OrganizationName: organization_name,
AlternateEmail: alternate_email,
TimeZoneID: time_zone_id,
UTCOffset: utcoffset,
DateCreated: date_created,
LastUpdatedDate: last_updated_date,
IsActive: is_active,
IsApproved: is_approved,
Classes: classes,
Groups: groups,
Permissions: permissions,
Properties: properties,
VersionStampHashString: version_stamp_hash_string,
GetFromData: getFromData
};
};
When I new up an APIUserItem by calling:
var user = new APIUserItem();
user.GetFromData(data);
then try to access the values in the new item like so:
document.write(user.ID);
all of the property values come back empty, except for the collections, which contain the expected data. For example, I can loop through the Groups array from outside the object and access the properties of each group to display values.
The data object I passed to the GetFromData function call contains all the data - it just seems like the assignments to the local variables are not working? I know I must have made some obvious mistake in my code. Can anyone help me find my problem?

Your assignments to the local variables are probably working, but they're just that: assignments to local variables. Your code does nothing to update the properties of the object. The fact that you create the object via that return statement that initializes properties from the local variables does not create a magic link between the local variables and the properties.
Your "getFromData" function should look something like this:
function getFromData( data ) {
this.ID = data.ID;
this.AccountID = data.AccountID;
// and so on
}
The collection properties ("classes", "groups", "permissions") worked because they're objects, and you update their contents. That part's OK. Really, you don't need those local variables at all; you can just initialize the object properties directly.

Related

how can you make an array save as a new object each time a function is executed and not overwrite my old array

I'm trying to make a simple register and log in system but I can only register 1 new username and password and the next time it is overwritten. I know the [2] after objpeople means it only writes on that line but what do put in to make it create a new object everytime?
var objpeople = [
{
username: "adam",
password: "coll",
email: "neilcoll#mail.com"
},
{
username: "jack",
password: "mc",
email: "jackmcgmail.com"
}
];
function register()
{
var Rusername = document.getElementById("Rname").value
var Rpassword = document.getElementById("Rpassword").value
var Remail = document.getElementById("Remail").value
var info = {};
objpeople.push(info);
objpeople[2].username=Rusername;
objpeople[2].password=Rpassword;
objpeople[2].email=Remail;
let convobjpeople = JSON.stringify(objpeople)
localStorage.people = convobjpeople
document.getElementById("logbtn").innerHTML = "Cart";
document.getElementById("logbtn").href="cart.html";
localStorage.setItem('logged', 'true');
return ;
}
edit: your code implementation
var objpeople = [
{
username: "neil",
password: "coll",
email: "neilcoll#gmail.com"
},
{
username: "jack",
password: "mc",
email: "jackmc#gmail.com"
}
];
function register()
{
let my_object = {
username: "",
password: "",
email: ""
}
var Rusername = document.getElementById("Rname").value
var Rpassword = document.getElementById("Rpassword").value
var Remail = document.getElementById("Remail").value
my_object.username=Rusername;
my_object.password=Rpassword;
my_object.email=Remail;
objpeople.push(my_object)
let convobjpeople = JSON.stringify(objpeople)
localStorage.people = convobjpeople
document.getElementById("logbtn").innerHTML = "Cart";
document.getElementById("logbtn").href="cart.html";
localStorage.setItem('logged', 'true');
return ;
}
Are you trying to create objects and push them into an array?
Just initiate an object
let my_object = {
username: "",
password: "",
email: ""
}
and when you want to assign values
var Rusername = document.getElementById("Rname").value
var Rpassword = document.getElementById("Rpassword").value
var Remail = document.getElementById("Remail").value
my_object.username=Rusername;
my_object.password=Rpassword;
my_object.email=Remail;
and finally
objpeople.push(my_object)
Edit:
It shouldn't really be behaving like this but either ways you could just create a replica object that is not passed on to a server. So for example create a objpeople2 and instead of objpeople.push(my_object) just do objpeople2.push(my_object) and then objpeople = objpeople2 and finally
let convobjpeople = JSON.stringify(objpeople). This way objpeople2 is kept as it is.

Better way to create an object from an object of properties?

In my app, I'm creating several different objects using data from an API request as follows:
const newRelationship = new Relationship(
data.id,
data.account_id,
data.name,
data.description,
data.created_at,
data.created_by,
data.deleted_at,
data.deleted_by,
data.updated_at,
data.updated_by,
);
This feels a bit cumbersome. Is there a better (one line) way to do this, rather than writing out all the parameters by hand like this?
I'm hoping for something like below but I'm not 100% on spread/destructuring yet.
const newRelationship = new Relationship(...data);
My Relationship constructor is as follows:
constructor(id, accountId, name, description, createdAt, createdBy, updatedAt, updatedBy, deletedAt, deletedBy) {
this.id = id || '';
this.accountId = accountId || '';
this.name = name || '';
this.description = description || '';
this.createdAt = createdAt || '';
this.createdBy = createdBy || '';
this.deletedAt = deletedAt || '';
this.deletedBy = deletedBy || '';
this.updatedAt = updatedAt || '';
this.updatedBy = updatedBy || '';
}
Simplify your constructor to:
const defaults = { id: "", name: "", /*...*/ };
//...
constructor(options) {
Object.assign(this, defaults, options);
}
Then you can just do:
new Relationship(data)
If you are writing the class/function (opinion) I would go with object destructuring in the parameters, it makes explicit that you are passing an object to the function and enumerates the properties (you can also rename them if you'd like in the destructure statement). If you are using code that can't be updated on your end I would suggest using array spread with Object.values()
class Relationship {
constructor({ id, account_id, name, description, created_at, created_by, deleted_at, deleted_by, updated_at, updated_by }) {
// do stuff with your variables
console.log(`ID is ${id}`);
}
}
class OtherRelationship {
constructor(id, account_id, name, description, created_at, created_by, deleted_at, deleted_by, updated_at, updated_by) {
// do stuff with your variables
console.log(`ID is ${id}`);
}
}
const dummyParams = {
id: 1,
account_id: 1,
name: 'test',
description: 'tesssst',
created_at: 'some date',
created_by: 1,
deleted_at: 'some date',
deleted_by: 1,
updated_at: 'some date',
updated_by: 1,
}
const newRelationship = new Relationship(dummyParams);
const newOtherRelationship = new OtherRelationship(...Object.values(dummyParams))

How to supply default values to ES6 class properties?

I have a JavaScript class I would like to supply with default values using an object. I only want the default values to be part of the class if user input is not otherwise supplied for some of the values. However, I am not sure how to implement this. Here is my class:
// Class definition, properties, and methods
class iTunesClient {
constructor(options) {
this.term = options.terms;
this.country = options.country;
this.media = options.media;
this.entity = options.entity;
this.attribute = options.attribute;
this.callback = options.callback;
this.limit = options.limit;
this.lang = options.lang;
this.version = options.version;
this.explicit = options.explicit;
this.url = options.url;
}
}
Here are my default values:
// Default values defined according to iTunes API
const defaults = {
terms: 'default',
country: 'US',
media: 'all',
entity: '',
attribute: '',
callback: '',
limit: 50,
lang: 'en-us',
version: 2,
explicit: 'yes',
url: '',
};
I realize this is possible through default parameters for functions, but I would rather supply an object containing the default values.
A typical way to do this is to use Object.assign() to merge passed-in values with default values:
// Class definition, properties, and methods
class iTunesClient {
constructor(options) {
// Default values defined according to iTunes API
const defaults = {
terms: 'default',
country: 'US',
media: 'all',
entity: '',
attribute: '',
callback: '',
limit: 50,
lang: 'en-us',
version: 2,
explicit: 'yes',
url: '',
};
let opts = Object.assign({}, defaults, options);
this.term = opts.terms;
this.country = opts.country;
this.media = opts.media;
this.entity = opts.entity;
this.attribute = opts.attribute;
this.callback = opts.callback;
this.limit = opts.limit;
this.lang = opts.lang;
this.version = opts.version;
this.explicit = opts.explicit;
this.url = opts.url;
}
}
To explain how Object.assign() works here:
It starts with {} as a target (an empty object)
Then it copies all the defaults into the empty object
Then it copies all the passed in properties into that same target
Then it returns the target object which you use for initializing all your instance data
Of course, if your instance property names are the same as the ones in your options object, you could do this in a more DRY fashion like this:
// Class definition, properties, and methods
class iTunesClient {
constructor(options) {
// Default values defined according to iTunes API
const defaults = {
terms: 'default',
country: 'US',
media: 'all',
entity: '',
attribute: '',
callback: '',
limit: 50,
lang: 'en-us',
version: 2,
explicit: 'yes',
url: '',
};
let opts = Object.assign({}, defaults, options);
// assign options to instance data (using only property names contained
// in defaults object to avoid copying properties we don't want)
Object.keys(defaults).forEach(prop => {
this[prop] = opts[prop];
});
}
}
You could do it like this:
class iTunesClient {
constructor(options) {
// Default values defined according to iTunes API
const defaults = {
terms: 'default',
country: 'US',
media: 'all',
entity: '',
attribute: '',
callback: '',
limit: 50,
lang: 'en-us',
version: 2,
explicit: 'yes',
url: '',
};
this.term = opts.terms || defaults.terms;
this.country = opts.country || defaults.country;
this.media = opts.media || defaults.media;
this.entity = opts.entity || defaults.entity;
this.attribute = opts.attribute || defaults.attribute;
this.callback = opts.callback || defaults.callback;
this.limit = opts.limit || defaults.limit;
this.lang = opts.lang || defaults.lang;
this.version = opts.version || defaults.version;
this.explicit = opts.explicit || defaults.explicit;
this.url = opts.url || defaults.url;
}
}
But you have to be wary of 'falsy' values, e.g. if opts.limit is passed in as 0 then this.limit will be set to defaults.limit value, even though opt was defined.
I think the better solutions for that, stackoverflow.com/a/48775304/10325885
class User {
constructor(options = {}) {
this.name = options.name || "Joe";
this.age = options.age || 47;
}
}
I think is much cleaner to read, if you just use ||.
For something a little more modern than the examples above you can use destructuring and default parameters.
class iTunesClient {
constructor({
term = '',
country = 'US',
media = 'all',
entity = '',
attribute = '',
callback = '',
limit = 50,
lang = 'en-us,
version = 2,
explicit = 'yes',
url = '',
}) {
this.term = terms;
this.country = country;
this.media = media;
this.entity = entity;
this.attribute = attribute;
this.callback = callback;
this.limit = limit;
this.lang = lang;
this.version = version;
this.explicit = explicit;
this.url = url;
}
}
That way any params that are not part of the constructor object will get set to the default. You can even pass an empty object and just get all defaults.

How to overwrite data from a multi dimensional array in javascript?

I got a multidimensional array where each array inside is a combination of all the user info (put in by the user)
I want the user to be able to modify his information, such as his name or phone number, so that the next time the user logs in, his new info is displayed.
The userList is saved on JSON, the idea would be for the changes to be saved and loaded from there.
Example:
if my array has
userList= JSON.parse(localStorage.getItem('userListLS')
if(userList == null) {
userList =
[
['Isaac', 'Garth', 'IsaacG11#email.com', 'Mazda']
['Matthew', 'Miller', 'mmiller21#mail.com', 'Volvo']
]
}
and lets say Isaac is logged in, and he wishes to change his name to Gabriel and change email to IsaacG21#email.com, so that the new array would be:
userList= [
['Gabriel', 'Garth', 'IsaacG21#email.com', 'Mazda']
['Matthew', 'Miller', 'mmiller21#mail.com', 'Volvo']
]
how could this be accomplished?
Only JS and HTML please.
The easiest approach would be to modify the data directly using index selectors:
This approach mutates the initial array instead of returning a new reference, which can lead to unwanted side effects.
function modifyData(data, userId, fieldId, newData) {
if(data[userId] && data[userId][fieldId]) {
data[userId][fieldId] = newData;
}
return data;
}
// example
var userList= [
['Isaac', 'Garth', 'IsaacG11#email.com', 'Mazda'],
['Matthew', 'Miller', 'mmiller21#mail.com', 'Volvo']
];
const FIELD_NAME_ID = 0;
const USER_ID = 0;
var modified = modifyData(userList, USER_ID, FIELD_NAME_ID, 'Morty')
console.log('initial', userList);
console.log('modified', modified);
An immutable approach would be:
function modifyData(data, userId, fieldId, newData) {
if(data && data[userId] && data[userId][fieldId]) {
var _data = data.slice();
var _user = data[userId].slice();
_user[fieldId] = newData;
_data[userId] = _user;
return _data;
}
return data;
}
// example
var userList= [
['Isaac', 'Garth', 'IsaacG11#email.com', 'Mazda'],
['Matthew', 'Miller', 'mmiller21#mail.com', 'Volvo']
];
const FIELD_NAME_ID = 0;
const USER_ID = 0;
var modified = modifyData(userList, USER_ID, FIELD_NAME_ID, 'Morty');
console.log('initial', userList);
console.log('modified', modified);
But you should consider changing your structure to a dictionary of objects:
{
user1: { name: 'Isaac', lastName: 'Garth' /* ... */ }
// ...
}
or an array of objects (but then you have to find the right user in the array:
[
{ name: 'Isaac', lastName: 'Garth' /* ... */ }
// ...
]
A good usecase for a Map:
const users = new Map(
userList.map(
( [first,name,email,car]) => [first, { first,name,email,car }]
)
);
So to change a certains users email:
users.get("Isaac").email = "test # gmail.com";
A few more usecases:
//set a whole user:
users.set("Jack", {
first:" Jack",
name:"Daniels",
email:"me#example.com",
car:"VW"
});
//get an array of users again
userList = [...users.values()];

Concise way to declare and load object

I have an object that I am creating and a function on that object to load data into the various properties. While the method works as desired, I feel like it might be redundant. Can this be accomplished in a more concise or better way?
var user = {
productLine: {
userActiveValue: []
},
id: {
PACT: null,
EDIPI: null,
AKO: null,
},
name: {
first: null,
last: null,
},
DMIS: null,
region: null,
email: null,
load: true,
loadUser: function (userInfoAPIResponse) {
this.id.PACT = userInfoAPIResponse.UID;
this.id.EDIPI = userInfoAPIResponse.EDIPN;
this.id.AKO = userInfoAPIResponse.akoUserID;
this.name.first = userInfoAPIResponse.fName;
this.name.last = userInfoAPIResponse.lName;
this.DMIS = userInfoAPIResponse.dmisID;
this.region = userInfoAPIResponse.RHCName;
this.email = userInfoAPIResponse.userEmail;
console.log(this);
}
};
function User(userInfoAPIResponse) {
this.id = {
PACT: userInfoAPIResponse.UID,
EDIPI: userInfoAPIResponse.EDIPN,
AKO: userInfoAPIResponse.akoUserID
};
this.productLine = {
userActiveValue: []
};
this.name = {
first: userInfoAPIResponse.fName,
last: userInfoAPIResponse.lName
};
this.DMIS = userInfoAPIResponse.dmisID;
this.region = userInfoAPIResponse.RHCName;
this.email = userInfoAPIResponse.userEmail;
}
var user = new User(...);
Aside from using e.g. user.name = {first: response.fName, last: response.lName} and so on, no. You need to map the variables from one object to another yourself, or just use the response as your user variable.
Alternatively you could just declare user as global (or outer) scope and both declare and set the sub-objects in your callback function. This would mean you potentially had to check for them and their parents being undefined before using them elsewhere, as opposed to a simple not null check.

Categories

Resources