Javascript - updating an object property with another value from the same object - javascript

I have the following object:
{ id: 1, name: 'jdoe', currentDayHours: null, totalHours: [{ task: 'cleaning', hours: 10}, { task: 'reading', hours: 2 }]}
I am trying to create a function that will update the currentDayHours based on the task parameter passed to the function. So for example, if "cleaning" is passed to the function, the expected outcome of the object should be:
{ id: 1, name: 'jdoe', currentDayHours: 10, totalHours: [{ task: 'cleaning', hours: 10}, { task: 'reading', hours: 2 }]}
I'm still new to javascript but I think I should use foreach and filter, but not sure how to use both with each other. Any guidance would be appreciated!

Direct property access is enough. Use Array.find to find the object.
data = { id: 1, name: 'jdoe', currentDayHours: null, totalHours: [{ task: 'cleaning', hours: 10}, { task: 'reading', hours: 2 }]}
const updateHours = (data,key) => {
data.currentDayHours = (data.totalHours.find(({task})=>task===key)||[]).hours
return data
}
console.log(updateHours(data,'cleaning'))

You can use Array.find() to find the task object in the totalHours array, and then use that object's hours to assign to currentDayHours.
If you want to modify the object in-place, you can do this:
function updateCurrentDayHours(obj, taskName) {
const task = obj.totalHours.find(t => t.task === taskName)
if (task) obj.currentDayHours = task.hours
}
If you want to return a cloned object, you can use a deepClone function provided by some libaries like lodash. Here I'm using JSON.parse() and JSON.stringify() for simplicity.
function updateCurrentDayHours(obj, taskName) {
const task = obj.totalHours.find(t => t.task === taskName)
if (task) {
const clone = JSON.parse(JSON.stringify(obj))
clone.currentDayHours = task.hours
return clone
}
}

Related

How can I get sibling value in JS object?

How can I get 'Pivot Grid', when I have 7? Is there method or can you help me with function?
WIDGET_TYPES = {
PIVOT_GRID: {
LABEL: 'Pivot Grid',
ID: 7,
},
DATA_GRID: {
LABEL: 'Grid',
ID: 4,
},
};
you can use Object.values and find
Object.values - will convert your object to array wiht next structure:
[{LABEL: 'Pivot Grid',ID: 7,}, ...]
after conversion you can apply find to new generated array.
In the find method you will pass your id(7) what need to find
then we need to take label from found element of array
const WIDGET_TYPES = {
PIVOT_GRID: {
LABEL: 'Pivot Grid',
ID: 7,
},
DATA_GRID: {
LABEL: 'Grid',
ID: 4,
},
};
const ID = 7;
const foundLabel = Object.values(WIDGET_TYPES).find(i => i.ID === ID)?.LABEL;
console.log('foundLabel: ', foundLabel)

ES6 reduce function affecting array outside of scope

I've rewritten this into a simplified form to demonstrate, I have an array of pickers who have an array of time entries, I'm using reduce to summarise time entries by type on the pickers & then a second reduce to show global entries across both pickers.
The first reduce per picker works as expected.
The second reduce on global time entries works as expected but somehow changes the entries for the first picker ( Sam ).
Sam & John pick the same amount.
Apples 2h, Peaches 2h, Lemons 1h
Is there a better way to write this? Is there a concept I've failed to understand?
function testBug() {
// Reducer Function
function entryReducer(summary, entry) {
// find an index if the types of fruit are the same
let index = summary.findIndex((item) => {
return item.type.id === entry.type.id;
});
if (index === -1) {
summary.push(entry);
} else {
summary[index].hours = summary[index].hours + entry.hours;
}
return summary;
}
let pickers = [
{
id: 1,
identifier: "Sam Smith",
timeEntries: [
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
{
type: {
id: 3,
name: "Lemons",
},
hours: 1,
},
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
],
},
{
id: 2,
identifier: "John Snow",
timeEntries: [
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
{
type: {
id: 3,
name: "Lemons",
},
hours: 1,
},
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
],
},
];
let pickersSummary = [];
let timeEntriesSummary = [];
for (const picker of pickers) {
if (picker.timeEntries.length > 0) {
// reduce time entries into an array of similar types
picker.timeEntries = picker.timeEntries.reduce(entryReducer, []);
// push to pickers summary arr
pickersSummary.push(picker);
// push time entries to a summary array for later reduce
picker.timeEntries.map((entry) => timeEntriesSummary.push(entry));
}
}
// Reduce time entries for all pickers
// Sam & John pick the same amount
// Apples 2h
// Peaches 2h
// Lemons 1h
// **** If I run this Sam's entries are overwritten with the global time entries ***
timeEntriesSummary = timeEntriesSummary.reduce(entryReducer, []);
const results = { pickersSummary, timeEntriesSummary };
console.log(results);
}
testBug();
module.exports = testBug;
Even though with each reducer you pass a new array [], the actual objects contained by these arrays could be shared. This means when you edit one of the objects in array "A", the objects could also change in array "B".
You know how some languages let you pass variables by value or by reference and how this fundamentally changes how values are handled? JavaScript technically uses call-by-sharing. I suggest reading this other answer: Is JavaScript a pass-by-reference or pass-by-value language?
once an element in an array is pushed into a different array it is separate in memory?
No, it isn't. In JavaScript you will always remember when you made an individual copy of an object (or at least wanted to), because that needs some effort, see What is the most efficient way to deep clone an object in JavaScript? or How do I correctly clone a JavaScript object?
So, just like when you use a=b, push(a) into an array refers the original object. See this example where there is a single object accessible via two variables (x and y), and via both elements of array z. So modifying it as z[1] affects all the others:
let x={a:5};
let y=x;
let z=[x];
z.push(y);
z[1].a=4;
console.log(x);
console.log(y);
console.log(z[0]);
console.log(z[1]);
As your objects are value-like ones and do not have anything what JSON would not support (like member functions), JSON-based cloning can work on them:
function testBug() {
// Reducer Function
function entryReducer(summary, entry) {
// find an index if the types of fruit are the same
let index = summary.findIndex((item) => {
return item.type.id === entry.type.id;
});
if (index === -1) {
//summary.push(entry);
summary.push(JSON.parse(JSON.stringify(entry))); // <--- the only change
} else {
summary[index].hours = summary[index].hours + entry.hours;
}
return summary;
}
let pickers = [
{id: 1, identifier: "Sam Smith", timeEntries: [
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},
{type: {id: 3, name: "Lemons",}, hours: 1,},
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},],},
{id: 2, identifier: "John Snow", timeEntries: [
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},
{type: {id: 3, name: "Lemons",}, hours: 1,},
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},],},];
let pickersSummary = [];
let timeEntriesSummary = [];
for (const picker of pickers) {
if (picker.timeEntries.length > 0) {
// reduce time entries into an array of similar types
picker.timeEntries = picker.timeEntries.reduce(entryReducer, []);
// push to pickers summary arr
pickersSummary.push(picker);
// push time entries to a summary array for later reduce
picker.timeEntries.map((entry) => timeEntriesSummary.push(entry));
}
}
// Reduce time entries for all pickers
// Sam & John pick the same amount
// Apples 2h
// Peaches 2h
// Lemons 1h
// **** If I run this Sam's entries are overwritten with the global time entries ***
timeEntriesSummary = timeEntriesSummary.reduce(entryReducer, []);
const results = { pickersSummary, timeEntriesSummary };
console.log(results);
}
testBug();
Now it probably displays what you expected, but in the background it still alters the pickers themselves, you have that picker.timeEntries = ... line running after all. It may be worth mentioning that const something = xy; means that you can not write something = yz; later, something will stick with a given entity. But, if that entity is an object, its internals can still be changed, that happens with picker.timeEntries above (while writing picker = 123; would fail).

json object from javascript nested array

I'm using a nested array with the following structure:
arr[0]["id"] = "example0";
arr[0]["name"] = "name0";
arr[1]["id"] = "example1";
arr[1]["name"] = "name1";
arr[2]["id"] = "example2";
arr[2]["name"] = "name2";
now I'm trying to get a nested Json Object from this array
arr{
{
id: example0,
name: name00,
},
{
id: example1,
name: name01,
},
{
id: example2,
name: name02,
}
}
I tought it would work with JSON.stringify(arr); but it doesen't :(
I would be really happy for a solution.
Thank you!
If you are starting out with an array that looks like this, where each subarray's first element is the id and the second element is the name:
const array = [["example0", "name00"], ["example1", "name01"], ["example2", "name02"]]
You first need to map it to an array of Objects.
const arrayOfObjects = array.map((el) => ({
id: el[0],
name: el[1]
}))
Then you can call JSON.stringify(arrayOfObjects) to get the JSON.
You need to make a valid array:
arr = [
{
id: 'example0',
name: 'name00',
},
{
id: 'example1',
name: 'name01',
},
{
id: 'example2',
name: 'name02',
}
];
console.log(JSON.stringify(arr));
Note that I am assigning the array to a variable here. Also, I use [] to create an array where your original code had {}.

How do you create Object of Arrays in Javascript

I spent more time on this than I would like to admit. I have trouble constructing an object filled with an array.
I would like my data to look like this:
items={
{
'2012-05-22': [{text: 'item 1 - any js object'}],
'2012-05-23': [{text: 'item 2 - any js object'}],
'2012-05-24': [],
'2012-05-25': [{text: 'item 3 - any js object'},{text: 'any js object'}],
}
}
I am making a database call and the data I receive looks like this:
Object {start: "08:00:00", end: "09:00:00", full_name: "Tomomi", date: "2017-06-08", Barber_id: "1"…}
The data I am interested in is the full_name value and the date value.
This is what I have attempted:
let newItems = {};
axios.post(endpoint, {lookup: day.dateString}).then((customerData) => {
customerData.data.forEach((val,key)=>{
newItems = {[val.date]:[]};
newItems[val.date].push({name:val.full_name});
console.log(newItems);
})
}
It looks like this:
Object {2017-06-08: Array(1)}
2017-06-08
:
Array(1)
This is very close, but the problem is that my code is overwriting my data.
I am trying to create this dynamically:
'2012-05-25': [{text: 'item 3 - any js object'},{text: 'any js object'}],
So that each date can have many users. Hopefully, this makes sense.
Thanks for any help.
The function expression you pass to forEach has this as the first line:
newItems = {[val.date]:[]};
This resets the newItems object to an object with one date:name pair. You really want something more like:
newItems[val.date]?newItems[val.date].push({name:val.full_name}):newItems[val.date]=[];
var byDate = {}; // Object to store received data by-date
function addIntoByDate( obj ) {
byDate[obj.date] = byDate[obj.date] || [];
byDate[obj.date].push( obj );
}
// Simulate adding server data one by one
addIntoByDate( {date: "2017-06-08", full_name: "Cat", text:"Foo!!"} ); // < SAME DATE
addIntoByDate( {date: "2016-05-23", full_name: "Dog", text:"Bar"} );
addIntoByDate( {date: "2017-06-08", full_name: "Bug", text:"Baz..."} ); // < SAME DATE
// test
console.dir(byDate);
You can use object destructuring, computed property and Object.assign()
const newItems = {};
const data = [
{
start: "08:00:00"
, end: "09:00:00"
, full_name: "Tomomi"
, date: "2017-06-08"
, Barber_id: "1"
}
];
data.forEach(({date, full_name}) =>
Object.assign(newItems, {[date]: [{/* text: */ full_name}]}));
console.log(newItems);

Create list of object members from object list

Assume I have a list of objects like so:
var list = [
{ date: '22/9/2016', status: 1, id: '11111' },
{ date: '23/9/2016', status: 1, id: '22222' },
{ date: '24/9/2016', status: 1, id: '33333' }
];
I would like to create a list of the ids of all the objects in the above list, so that I end up with:
var idList = ['11111', '22222', '33333'];
Obviously, I could iterate through the list and build the idList manually.
Is there an alternative way of doing this through either native JS, angularJS, or perhaps another library.
Manually iterating through the list isn't a big overhead, I just want to ensure I'm not ignoring functionality of JS / angularJS that would do this for me instead.
You can use Array map
var list = [
{ date: '22/9/2016', status: 1, id: '11111' },
{ date: '23/9/2016', status: 1, id: '22222' },
{ date: '24/9/2016', status: 1, id: '33333' }
];
var idList = list.map(item => item.id );
console.log(idList);
Use
var ids = list.map(function(item) { return item.id});
Should work.

Categories

Resources