I want to extend an object in a specific position in an array, without having to send the whole array again.
Example:
You start out with the array like this:
sensors = [{value: 10}, {value: 20}];
Now say I want to change the value of the second sensor, I can do this in jQuery:
newSensorValue = {1: {value:30}};
$.extend(true, sensors, newSensorValue);
// sensors = [{value: 10}, {value: 30}];
However, if the array is not directly the object that is merged, this does not work:
node = {x: 10, y: 10, node_id: 1, sensors: [
{sensor_id: 1, value: 10},
{sensor_id: 2, value: 20}
]};
newNodeData = {sensors: {
1: {value:30}
}};
$.extend(true, node, newNodeData);
// node = {x: 10, y: 10, node_id: 1, sensors: {
// 1: {value:30}
// }};
Why does $.extend() suddenly behave differently if the array is nested in an object?
My own solution would be to create an array of empty objects, only giving the object that I want to change the "value" attribute, like:
newNodeData = {sensors: [
{}, {value: 30}
]};
Since this seems rather ugly, is there a better way to do this?
I would prefer to keep the sensors attribute an array, since I like to use forEach to go through each sensor quickly.
EDIT: forgot to mention that if I do
$.extend(true, node.sensors, newNodeData.sensors);
It works the same as in the first example (i.e. it works)
You could leave the element empty when you don't want to change it.
node = {x: 10, y: 10, node_id: 1, sensors: [
{sensor_id: 1, value: 10},
{sensor_id: 2, value: 20}
]};
newNodeData = {sensors: [,{value:30}]};
$.extend(true, node, newNodeData);
Related
Say I have some objects like what's shown below. What I want to do is refer to the index positions in myObjects. For example, myObjects[0].parameter1 would be give me blue. However referencing stuff by index positions doesn't seem to work in objects. Am I just getting the syntax wrong or is this just not possible with javascript?
let myObjects= {
objectA:{
parameter1: blue,
parameter2: 5,
},
object B:{
parameter1: orange,
parameter2: 4,
},
}
Updated post below
let myObjects = [
{
parameter1: 'blue',
parameter2: 5,
},
{
parameter1: 'orange',
parameter2: 4,
},
]
let obj = myObjects.find(o => o.parameter1 === 'blue');
console.log(obj)
I also included how you can find that object with a specific parameter, in this case blue and then return it to a variable. Obviously im just console logging the object, but you can use it for whatever you want.
I have this piece of code, but whenever I run findTimeSlots() it immediately messes up my global array apptData but I don't see in anywhere in this function that is supposed to have changed it.
(ConsoleLog)
(index):69
(4) [{…}, {…}, {…}, {…}]
0: {service: "A, B", duration: 50, tech: "C"}
1: {service: "B", duration: 30, tech: "C"}
2: {service: "A, D", duration: 60, tech: "A"}
3: {service: "D", duration: 40, tech: "A"}
length: 4
__proto__: Array(0)
(index):45
(4) [{…}, {…}, {…}, {…}]
0: {service: "A, B", duration: 50, tech: "C"}
1: {service: "B", duration: 30, tech: "C"}
2: {service: "A, D", duration: 60, tech: "A"}
3: {service: "D", duration: 40, tech: "A"}
length: 4
__proto__: Array(0)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var apptData = [];
function addApptData(serviceName, rawDuration, selectedTech){
apptData.push({
'service': serviceName,
'duration': rawDuration,
'tech' : selectedTech
})
}
function reduceApptData(index){
apptData.splice(index, 1);
}
function findTimeSlots(dateStr){
console.log(apptData); //* Index 45 *//
var final = new Array();
var service, duration;
for(var i = 0; i < apptData.length; i++){
var duplicated = false;
for(var j = 0; j < final.length; j++){
if(final[j].tech == apptData[i].tech){
service = ", "+apptData[i].service;
final[j].service += service;
duration = apptData[i].duration;
final[j].duration += duration;
duplicated = true;
break;
}
}
if(!duplicated){
final.push(apptData[i]);
}
}
}
addApptData("A", 20, "C");
addApptData("B", 30, "C");
addApptData("A", 20, "A");
addApptData("D", 40, "A");
console.log(apptData); //* Index 69 *//
// If I remove the line below, I get the expected result, when I try to
// run with this line it will mess up apptData[]
findTimeSlots("");
What I expected to be is
0: {service: "A", duration: 20, tech: "C"}
1: {service: "B", duration: 30, tech: "C"}
2: {service: "A", duration: 20, tech: "A"}
3: {service: "D", duration: 40, tech: "A"}
length: 4
__proto__: Array(0)
So basically I expect it to remain the same.
I wanted to consolidate my var apptData into my var final inside my findTimeSlots()
After debugging, I found out that my apptData keep changing unexpectedly for some reason.
I suspect this to be very trivial but I cannot for the life of me figure out.
What is happening is explained in this tiny example:
let a = {test: 10};
let b = a;
b.text = 11;
console.log(a); //this will print {test: 11}
Since a is an object, when you assign let b = a; you are actually saving a reference to a, not cloning a.
You need to clone the object apptData[i], and to do that See this answer
So instead of final.push(apptData[i]); you should push a cloned apptData[i].
Hope that helps.
You should make a shallow copy of apptData.
One thing you should take note of JavaScript is the difference between assignment by value vs assingment by reference.
When primitive data types such as numbers(i.e. 2, 23), strings (i.e 'aaa', '123') are assigned to a variable, the variable contains the primitive value.
On the other hand, when non-primitive data types (arrays, objects, functions) are assigned to a variable, the variable contains the reference (which 'points' to the object's location on the memory), rather than the value itself.
To answer your question, you should be making a shallow copy of apptData, rather than making a direct reference to it.
Assuming that your apptData is an array of (non-nested) objects, here is a simply way to make a shallow copy of it using ES6's spread syntax:
const apptDataCopy = apptData.map(serviceObject => ({...serviceObject}));
From there, you can make any changes you wish to apptDataCopy, and it will not affect the original apptData.
var apptData = [], typeSelectedTech = new Set(), finalData =[], tmpObj = {serviceName: '', rawDuration: 0}
const addApptData = (serviceName, rawDuration, selectedTech)=> {
apptData.push({
serviceName,
rawDuration,
selectedTech
})
if (typeSelectedTech.has(selectedTech)) {
finalData.push({serviceName: tmpObj.selectedTech + ',' + serviceName, rawDuration: tmpObj.rawDuration + rawDuration, selectedTech})
}else {
tmpObj = {
serviceName,
rawDuration,
selectedTech
}
typeSelectedTech.add(selectedTech)
}
}
addApptData("A", 20, "C");
addApptData("B", 30, "C");
addApptData("A", 20, "A");
addApptData("D", 40, "A");
console.log(finalData);
console.log(apptData);
First of all, I believe that you have solved the problem, my answer is only for communication.
I tried the rewriting method, you can get the raw data and the target data. Although it produces multiple global variables, I can't think of other ways.
So as a communication, I hope other people can have a better way.
I have a JavaScript object that looks like this:
Const data = {
x: 1,
y: 2,
z: 3
a: 4,
b: 5,
c: 6
};
We have a signing service in our Angular 6 application which stringifies this object, hashes the string, then attached a signature to it. Then it saves it to a firestore database. The database likes to order the properties alphabetically so it ends up looking like this:
{
a: 4,
b: 5,
c: 6,
x: 1,
y: 2,
z: 3
}
When we retrieve this object from the database and try to validate the signature, it fails. It fails because when you stringify this object, the alphabetical order of the properties results in a different string compared to when we signed it. This results in a different hash which doesn’t match with the original signature.
Our current solution to this problem is that we write out the order of the properties alphabetically in the code, but we’d like to make this fool proof (ex. If another developer comes along and adds a property to the bottom, say d, not realizing it’s supposed to be alphabetical). I’m told by a colleague that there is some way of telling Javascript to order the properties according to its own algorithm. If we could do that, then we’d order the properties according to that algorithm before stringifying, hashing, and signing, and then when we retrieve the object from the database, do the same thing: order the properties according to Javascript’s algorithm, stringify, hash, and validate.
Does anyone know what this Javascript ordering is and how to do it?
There isn't a way for JS to naturally order an object, you're going to have to tinker with it yourself.
The easiest way that I can think of to do this would be to use an array and sort from there.
This will return you the following array...
Object.entries(test).sort((a, b) => a[1] - b[1])
returns
[ [ 'x', 1 ],
[ 'y', 2 ],
[ 'z', 3 ],
[ 'a', 4 ],
[ 'b', 5 ],
[ 'c', 6 ] ]
If you want it back in an object,
Object.assign({}, ...Object.entries(test).sort((a, b) => a[1] - b[1]).map(([key, value]) => ({[key]: value})) )
returns
{ x: 1, y: 2, z: 3, a: 4, b: 5, c: 6 }
Create a custom stringify function that handles putting the object in the correct order.
const data = {
a: 4,
b: 5,
c: 6,
x: 1,
y: 2,
z: 3
}
function customStringify(d){
return '{'+Object
.entries(d)
.sort(([,v1],[,v2])=>v1-v2)
.map(([k,v])=>`${k}:${v}`)
.join(",")+'}';
}
const res = customStringify(data);
console.log(res);
I would like to filter on a particular object property. If that property is false OR undefined/null, I want it included. In the example below, I am summing by the deliciousRating as long as isBruised is not true. However, I can't figure out how to include the undefined/null value.
var apples = [
{isBruised: true, deliciousRating: 1},
{isBruised: false, deliciousRating: 10},
{deliciousRating: 9}
];
_.sumBy(_.filter(apples, ['isBruised', false]), 'deliciousRating');
I would like this to return 19, but currently it is only getting the deliciousRating from apples[1].
Use _.reject() instead of _.filter(). The _.reject() method is...
The opposite of _.filter; this method returns the elements of
collection that predicate does not return truthy for.
var apples = [
{isBruised: true, deliciousRating: 1},
{isBruised: false, deliciousRating: 10},
{deliciousRating: 9}
];
var result = _.sumBy(_.reject(apples, 'isBruised'), 'deliciousRating');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
And in vanilla JS, you can use Array#reduce to sum just the items that are not bruised:
var apples = [
{isBruised: true, deliciousRating: 1},
{isBruised: false, deliciousRating: 10},
{deliciousRating: 9}
];
var result = apples.reduce(function(s, o) {
return o.isBruised ? s : s + o.deliciousRating;
}, 0);
console.log(result);
I would use native filter function .filter((v) => !v.isBruised). Will include deliciousRating key either if isBruised is null, undefined, false or if doesn't exist.
const apples = [
{isBruised: true, deliciousRating: 1},
{isBruised: false, deliciousRating: 10},
{deliciousRating: 9}
];
const r = _.sumBy(apples.filter((v) => !v.isBruised), 'deliciousRating');
console.log(r);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
I am using angularjs where I have a $scope.var1 ={a:10, b:20, c:30}; in which I want to append another value(s) which is infact an array of objects i.e. $scope.myobjects=[{m:10, n:30}, {x:6, y:8}, ....]; after appending this value my $scope.var1 should look like, $scope.var1={a:10, b:20, c:30, m:10, n:30, x:6, y:8};
any idea please.
Thanks
obj ={a:10, b:20, c:30};
arr=[{m:10, n:30}, {x:6, y:8}];
arr.forEach(function(a){
Object.keys(a).forEach(function(key){
obj[key]=a[key];
})
})
console.log(obj);
You could iterate the array and use Object.assign.
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
If not on the user agent available, like on IE, you could use a polyfill.
var target = { a: 10, b: 20, c: 30 };
objects = [{ m: 10, n: 30 }, { x: 6, y: 8 }];
objects.forEach(function (o) {
Object.assign(target, o);
});
console.log(target);
Object.assign.apply(null, [$scope.var1].concat($scope.myobjects))
Please try this one:
var var1 = { a: 10, b: 20, c: 30 };
myobjects = [{ m: 10, n: 30 }, { x: 6, y: 8 }];
myobjects.forEach(function (o) {
for (var p in o) {var1[p] = o[p]};
});
console.log(var1);
Note that this code simply add/update properties based on source object