Adding object when nested in Javascript with ES6 - javascript

I am trying to add an object, but it seems like it is overwriting instead of being added.
I have an initial object:
const config = {
person: 'Bob',
employer: 'yahoo',
}
I'm making a new object elsewhere like so:
const newConfig = {
...config,
customText: { [myVar]: messageText },
[myVar]: selectedItem,
};
myVar can be either message or note that gets sent to Bob.
First, you write a message to Bob, so newConfig looks like this:
const config = {
person: 'Bob',
employer: 'yahoo',
customText: { message: 'hi bob!' }
}
But then later I add a note, and I want the result to be:
const config = {
person: 'Bob',
employer: 'yahoo',
customText: { message: 'hi bob!', note: 'please leave a message for Bob' }
}
Instead, it seems like my object is being overwritten.
const config = {
person: 'Bob',
employer: 'yahoo',
customText: { note: 'please leave a message for Bob' }
}
I've tried to use Object.assign, but I end up in a similar conundrum.
const customText = Object.assign({}, newConfig.customText, {[myVar]: messageText});
I've also tried doing something with the object assignation:
const newConfig = {
...config,
customText[myVar]: messageText,
[myVar]: selectedItem,
};
But I'm getting an Parsing error: Unexpected token, expected ","
How can I add the object without overwriting it?

You need to spread customText too, else it replaces the customText with new property everytime
const newConfig = {
...config,
customText: {...config.customText, [myVar]: messageText },
[myVar]: selectedItem,
};

Related

Change a value from a nested object using localstorage

I have this code that set the obj value in localstorage.
const obj = {
name: "Bill",
meta: {
age: 18
}
};
const data = localStorage.setItem('user', JSON.stringify(obj));
Now i want to change the age key in the localstorage:
localStorage.setItem('user', JSON.stringify({ ...data, ...data.meta.age= 15 } }));, but it does not work.
How to change the value above and to see the changes in localstorage?
Assuming you have data, the problem is that ...data.meta.age = 15 is a syntax error. You don't use = in object literals, and it does't make sense to try to spread the age property (which is a number). Instead:
const newData = {
...data,
meta: {
...data.meta,
age: 15,
},
};
localStorage.setItem("user", JSON.stringify(newData));
Notice how we have to create a new outermost object and also a new object for meta.
Live Example:
const data = {
name: "Bill",
meta: {
occupation: "Programmer", // Added so we see it get copied
age: 18,
},
};
const newData = {
...data,
meta: {
...data.meta,
age: 15,
},
};
console.log(newData);

Simplify nested for loop

I have this code:
let peopleInRoom = [];
for (let message of messages) {
for (let email of message.user.email) {
if (!peopleInRoom.includes(email)) {
peopleInRoom.push(email);
}
}
}
let peopleInRoomElement = peopleInRoom.map(person => (
<li>{person}</li>
))
Basically I am trying to get all the unique emails and display them.
Is there a shorter and more efficient way (maybe some ES6 features) to write the same code? Seems too much code than needed.
I looked at this answer: How to get distinct values from an array of objects in JavaScript?
EDIT: Above code does not do what I want.
My data looks like this:
[
{
text: 'foo',
user: { email: 'foo#bar.com', password: 'foo' }
},
{
text: 'baz',
user: { email: 'baz#qux.com', password: 'baz' }
}
]
The objects are all messages. And I want to get an array of all the unique emails from each message
You can use the Set object that is built into JavaScript. Set object actually keep the distinct primitive values.
const messages = [
{
text: 'foo',
user: { email: 'foo#bar.com', password: 'foo' }
},
{
text: 'baz',
user: { email: 'baz#qux.com', password: 'baz' }
}
]
const peopleInRoom = [...new Set(messages.map(message => message.user.email))];
It actually extracts the email from each message and then passes it to the Set object which only keeps the unique set of emails. After that, it will spread that Set to the array, since Set is also an iterable and returns the array of the people in room.
If I understand correctly, people have messages, messages have email addresses and the OP seeks the unique set of email addresses. If that's all the data available, then there's no alternative but to iterate it, checking to see if each email has been collected already, and collecting it if it hasn't been.
There are ways to conceal this work by doing it in library code. Probably the highest level utility is lodash's _.uniqueBy, but the work must be done one way or another.
The Set object enforces uniqueness of its elements. You can use it this way:
const peopleInRoom = Array.from(new Set(messages.map(message => message.user.email)));
First you can make an array of all the email addresses:
const data = [
{
text: 'foo',
user: { email: 'foo#bar.com', password: 'foo' }
},
{
text: 'baz',
user: { email: 'baz#qux.com', password: 'baz' }
}
]
const emailArray = data.map((elem) => {
return elem.user.email;
}
and then you can filter them to be unique:
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
emailArrayFiltered = emailArray.filter(onlyUnique);
see here for ref link
What about:
const peopleInRoom = messages.map(e => e.user.email && e.user.email);
console.log(peopleInRoom)
gives you this output:
["foo#bar.com", "baz#qux.com"]

Replacing key value in array of objects

I'm working on a project that is a basic message app. basically i have created an array of objects that allows me to see pre built messages. Then i should be able to click a clear all button and clear all of the messages that are being displayed by looping through the array of objects. this is what i have so far in my messageData.js
const messages = [
{
id: 'message1',
message: 'Hello everyone! Welcome to hell',
userId: 'user1',
},
{
id: 'message2',
message: 'Yall are weirdos!',
userId: 'user3',
},
{
id: 'message3',
message: 'Hey! I think everyone is awesome!',
userId: 'user2',
},
{
id: 'message4',
message: 'Thanks for saying that my friend.',
userId: 'user4',
},
{
id: 'message5',
message: 'Hey buddy, what is up?',
userId: 'user4',
},
];
const getMessages = () => messages;
and what i want to do is basically on click allow the messages key value to be changed to an empty string onclick so that i get rid of the displayed messages without getting rid of the object so that i can later push new messages into these key values.
I started to write this but i seem to be missing something..
const clearBtnFunction = () => {
messages.splice(1, '');
};
i'll be calling the event listener on my main.js file so i'm not super worried about that part yet. I just want to know the proper syntax for replacing the key value in the array if thats possible.
Here is what i opted for. I placed this function, not in the messagesData.js but in the messages.js where i'm building the domstring
const clearBtnFunction = (e) => {
e.preventDefault();
const messages = message.getMessages();
messages.splice(0, messages.length);
messageBuilder(messages);
};
const clearBtnFunction = () => {
messages.foreach( ( message ) => {
message.message = "";
});
};
or with a for loop
const clearBtnFunction = () => {
for( let i =0; i < messages.length; i++) {
messages[i].message = "";
}
};

How to I empty an array in the state before updating it gain?

I want to empty the array in the state before adding to it again
this.state = {
arrayOne = [
{
name: 'first n',
last: 'last n'
},
{
name: 'first Name',
last: 'last Name'
}
]
}
this.setState({arrayOne: []}) //not emptying the array
this.setState({arrayOne: [...arrayOne.splice()]}) //also not working
Why do you say its not working? The syntax looks fine and should work
Please note that setState is an async function, you need to wait for the update to complete in order to see change.
You can pass a callback function to setState, that will get executed when the state was set, like so
this.setState({
blah: 'something new'
}, () => {
console.log(this.state.blah) // will print 'something new'
}
})
You will not see immediate change if you do it like this:
this.setState({
blah: 'something new'
})
console.log(this.state.blah) // this will print whatever 'blah' was previously set to, and not 'something new'
Try like this..
this.state.arrayOne = [];
or
this.state['arrayOne'] = [];

How to load mobx state from json?

I want to store my mobx state in browser localStorage, so, if i use this approach https://stackoverflow.com/a/40326316
I save store with toJS, but don't know how to apply it. With extendObservable I get following error Error: [mobx] 'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead
Thanks in advance.
My approach is:
class MyStore {
...
public async load() {
const cached = await browser.storage.local.get("cache");
const data = JSON.parse(cached["cached"]);
Object.keys(data).forEach(x => {
(this as any)[x] = (data as any)[x];
});
...
}
But i think this is anitpattern.
Are you sure extendObservable doesn't work.
I've used something like this in my code.
class MyStore {
async load() {
const cached = await browser.storage.local.get("cache");
mobx.extendObservable(this, cached);
}
}
Edit:
This seems to be not working, you need to access the properties after extendObservable in order to reload them, you could use autorun but just use another method.
I've implemented load function based on a simple forEach;
Try the following.
load = async () => {
const { cache } = await JSON.parse(localStorage.getItem("cache"));
Object.keys(cache).forEach(key => {
this[key] = cache[key];
});
};
CodeSandbox
https://codesandbox.io/s/late-snow-xppx0?ontsize=14&hidenavigation=1&theme=dark
If you have a class, and "raw" json data, what i'm doing is to accept raw data in the constructor & then update the class properties.
For example, my raw data looks like this:
{
users: [
{ id: 1, firstName: 'foo', lastName: 'bar', customer: { id: 1, name: 'bla' } },
{ id: 2, firstName: 'foo2', lastName: 'bar2', customer: { id: 2, name: 'customer' } },
];
}
class User {
id;
#observable firstName;
#observable lastName;
customer;
constructor(rawUser) {
this.id = rawUser.id;
this.firstName = rawUser.firstName;
this.lastName = rawUser.lastName;
this.customer = new Customer(rawUser.customer);
}
}
class UsersStore {
#observable users = [];
constructor(rawUsers) {
this.users = rawUsers.map(rawUser => new User(rawUser));
}
}
Then when I'm restoring the data I'm just using
const usersStore = new UsersStore(rawData.users);
The cool thing in this approach is the nesting handling, each "level" handles its part.

Categories