i am not getting proper the return after insertgraph in objection.js
i am getting the result like :
[
User {
name: 'Santosh Devi',
city: 'Suratgarh',
number: '9898987458',
userroles: UserRoles { role_id: 2, user_id: 37 },
id: 37
}
]
where i want the result like :
[
{
name: 'Santosh Devi',
city: 'Suratgarh',
number: '9898987458',
userroles: { role_id: 2, user_id: 37 },
id: 37
}
]
There are few ways to get rid of the specific class references:
1. JSON.parse(JSON.stringify(result))
This will rebuild the object by first converting the whole object to a string (in JSON format), and then by doing the reverse -- creating a new object from a string. As this string format (JSON) does not store custom class information, it achieves your purpose. However, if your object has functions, symbols, then these will be omitted. Also Map and Set will become empty objects. For a more complete list of restrictions. See JSON.stringify
2. Deep Clone
There are several deep-clone functions out there, that may or may not do what you expect. Some will still try to maintain the original prototype references, so that it would not benefit you. You can find some here: How to Deep clone in javascript. For your case, this one would do the job:
function deepClone(obj, hash = new WeakMap()) {
if (Object(obj) !== obj) return obj; // primitives
if (hash.has(obj)) return hash.get(obj); // cyclic reference
const result = Array.isArray(obj) ? [] : {};
hash.set(obj, result);
return Object.assign(result, ...Object.keys(obj).map(
key => ({ [key]: deepClone(obj[key], hash) }) ));
}
You call it as newResult = deepClone(result).
The advantage here, is that it supports cyclic references, which JSON.stringify cannot handle. Also, there is no string conversion happening, which really is not necessary. You can extend this function to keep deal with some class instances that you like to stay that way. See how you can support Date, RegExp, Map, Set, ... in this answer. But don't do the "catch-all" line.
3. Change the prototype
With this strategy you mutate the result in-place.
function removeClasses(obj, hash = new WeakSet()) {
if (Object(obj) !== obj) return; // primitives
if (hash.has(obj)) return; // cyclic reference
hash.add(obj);
if (Array.isArray(obj)) Object.setPrototypeOf(obj, Array.prototype);
else Object.setPrototypeOf(obj, Object.prototype);
for (let value of Object.values(obj)) {
removeClasses(value, hash);
}
}
Call it as removeClasses(result), and afterwards result will have been "fixed". Again, this method does not use a conversion to string. As it does not create a new object either, it consumes less memory. But on the other hand you mutate an object, and some would advise against that.
Dynamically I'm getting several objects having the following structure.
obj1 = {
prop: 'one',
key: 'string',
value: 2
}
obj2 = {
prop: 'one',
key: 'diffString',
value: 3
}
Also, I have an object which I want to turn into this using received objects.
mainObject = {
prop: {
key1: value,
key2: value
}
}
I'm trying to use this
mainObject[obj.prop][obj.key] = obj.value;
But it gives me an error because at this point mainObject is just an empty object and it doesn't have mainObject[obj.prop]
Any help will be much appreciated.
The simplest way to achieve this is as follows:
// If no value for obj.prop exists, assign empty object
mainObject[obj.prop] = mainObject[obj.prop] || {};
// Assign value to obj.key of object at mainObject[obj.prop]
mainObject[obj.prop][obj.key] = obj.value;
This code is first ensuring that a valid value (object) exists at the key obj.prop on mainObject. If there is not valid object at key obj.prop, then a new empty object is assigned {}.
The mainObject[obj.prop][obj.key] = obj.value assignment can now be performed safely seeing that an object exists at mainObject[obj.prop].
Alternatively, if you want a more concise way of doing this you could consider the lodash library which offers the .set() method:
_.set(mainObject, obj.prop + '.' + obj.prop, obj.value);
Hope this helps!
all you can do is push your upcoming object into an array and by using reduce method you can simply achieve your desired output
let mainObject = [obj1, obj2].reduce((result, obj) => {
result[obj.prop] = result[obj.prop] || {};
result[obj.prop][obj.key] = obj.value;
return result;
}, {});
I am currently unsure as to how to edit one of my objects in my javascript (React JS) program. I am implementing web sockets into my program, and so I am receiving an object that I need to use to edit another object in my program.
Here are the two summarized objects (with only updated properties included):
objectWeAreEditingWith = {
path: [
"playerStatuses",
"id1" //really is an id like "b02a507f-31..."
],
value: [
true,
"Random"
]
}
objectWeAreEditing = {
property1: ...
property2: ...
...
playerStatuses: {
id1: [
false,
"Generalist"
]
}
...
moreProperties: ...
}
Some details about the objects. The "objectWeAreEditingWith" will always only have a path and value property. The path property just contains the keys that are required access the correct key in "objectWeAreEditing". The value property just contains the variable values to change in the key that was detailed in the path property. "ObjectWeAreEditing" can contain any number of properties. Another thing to note is that the values in the array "value" is always in the same order (and size) as the property we are targeting in "objectWeAreEditing". "path", "value", and "id1" could techincally be any size (very long path / many variables), but id1 and value will always have the same length / have the values in the same order like I said before.
For this case, I am trying to do:
objectWeAreEditing[playerStatuses][id1][0] = objectWeAreEditingWith[value][0];
AND
objectWeAreEditing[playerStatuses][id1][1] = objectWeAreEditingWith[value][1];
The problem is that, of course, I don't know that I am editing:
objectWeAreEditing[playerStatuses][id1]
because this path is given by "objectWeAreEditingWith".
I also don't know that I am only editing:
objectWeAreEditing[playerStatuses][id1][0];
AND
objectWeAreEditing[playerStatuses][id1][1];
because the amount of variables I am editing is given in "objectWeAreEditingWith".
The solution for the second portion is to go into the "value" property and check its length and iterate through that many variables inside of (id1 in this case). I do not, however, have any clue how to iterate through a path of keys inside of an object.
If you want to set data in object2 depending on object1, one solution is:
let object1 = {
path: [
"playerStatuses",
"id1"
],
value: [
true,
"Random"
]
};
let object2 = {
property1: true,
property2: true,
playerStatuses: {
id1: [
false,
"Generalist"
]
}
};
console.log(object2);
(function setObjectFrom(object1, object2) {
var i = 0;
if (object1.path.length <= 0) {
throw "Cannot set empty path";
}
var currentToKey = object1.path[i];
(function walkerObject(object, value) {
for (let key in object) {
if (key == currentToKey) {
if (object1.path.length-i <= 1) {
object[key] = value;
}
else {
i++;
currentToKey = object1.path[i];
walkerObject(object[key], value); // call itself
}
}
}
})(object2, object1.value);
})(object1, object2);
console.log(object2);
Here:
A function (setObjectFrom) is defined to set an attribute of a object2 depending of object1.path and object1.value. It define another function named walkerObject. This function does the following: each time it find a value of path (let name it vPath) as a key of object1, it verify if it is the last key:
When it is the last key, it set value as value of object2[vPath]
If it is not the last key, the walkerObject call itself again looking for the next value of path, but with object2[vPath] as object2
This function is not bullet proof, that mean, it does not handle error such as object1.path is not found inside object2 and others case.
Corresponding jsBin
Suppose that I have this code:
var cfg = {
config: {
fields: {
name: {
type: 'text'
},
age: {
type: 'number'
}
},
actions: [
{
label: 'Print',
cb: (model) => {
console.log(model);
}
}
]
},
data: {name: 'Jhon', age: 23}
}
And I want to convert it to a string (to let a user edit it) and then convert it back to executable code, any idea in how to achieve this?
I tried with JSON.stringify and JSON.parse but that will of course strip the functions. .toString returns "[object Object]", iterating on the object and call .toString when the values is a string, function or number is a possibility, any other idea?
The Function constructor takes code as string, so does eval and a couple other. However, if in any way avoidable, do not convert code to string and backwards because of security concerns, ability to debug and a lot of other issues you can run into when doing so.
Converting code to a string is slightly annoying, because you need to make sure you don't redeclare variables and everything in the new context is syntactically correct, e.g. note that obj's f property is again named in the declaration, because it is later given to eval which places it in the global scope where it needs a name.
let obj = { f: function f() { let stuff = "hi"; console.log("hi"); } };
let code = obj.f.toString();
console.log(code);
eval(code);
f();
Note that JSON.stringify has an optional replacer parameter which can be used to customize the process.
I will again highly advise to avoid any code to/from string conversions when possible, in all normal cases this is not needed and should not be done.
You can iterate around that object and set it to inputs elements, like this
for (var key in cfg.config.fields) {
console.log(key, cfg.config.fields[key].type);
console.log(key, cfg.data[key],'data');
console.log('<input type="'+cfg.config.fields[key].type+'" value="'+cfg.data[key]+'">')
}
This is the solution I came up with:
const toString = (code) => {
if(Array.isArray(code)){
return code.map(item => toString(item));
}
else if(typeof code == 'object'){
let tmp = {};
Object.keys(code).forEach(key => {
tmp[key] = toString(code[key])
});
return tmp;
}
else{
return code.toString().split('\n').join('').replace(/ +(?= )/gmi, '');
}
};
This will iterate recursively across all the properties in a random JS structure (an object containing objects and arrays) an return the corresponding structure containing strings, you can then use JSON.stringify to get the actual string.
After the user edited it, it is executed with:
eval(`(${string})`);
As noted by other, be careful using eval, it can be dangerous (an interesting article is https://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/)
I get from the server a list of objects
[{name:'test01', age:10},{name:'test02', age:20},{name:'test03', age:30}]
I load them into html controls for the user to edit.
Then there is a button to bulk save the entire list back to the database.
Instead of sending the whole list I only want to send the subset of objects that were changed.
It can be any number of items in the array. I want to do something similar to frameworks like Angular that mark an object property like "pristine" when no change has been done to it. Then use that flag to only post to the server the items that are not "pristine", the ones that were modified.
Here is a function down below that will return an array/object of changed objects when supplied with an old array/object of objects and a new array of objects:
// intended to compare objects of identical shape; ideally static.
//
// any top-level key with a primitive value which exists in `previous` but not
// in `current` returns `undefined` while vice versa yields a diff.
//
// in general, the input type determines the output type. that is if `previous`
// and `current` are objects then an object is returned. if arrays then an array
// is returned, etc.
const getChanges = (previous, current) => {
if (isPrimitive(previous) && isPrimitive(current)) {
if (previous === current) {
return "";
}
return current;
}
if (isObject(previous) && isObject(current)) {
const diff = getChanges(Object.entries(previous), Object.entries(current));
return diff.reduce((merged, [key, value]) => {
return {
...merged,
[key]: value
}
}, {});
}
const changes = [];
if (JSON.stringify(previous) === JSON.stringify(current)) {
return changes;
}
for (let i = 0; i < current.length; i++) {
const item = current[i];
if (JSON.stringify(item) !== JSON.stringify(previous[i])) {
changes.push(item);
}
}
return changes;
};
For Example:
const arr1 = [1, 2, 3, 4]
const arr2 = [4, 4, 2, 4]
console.log(getChanges(arr1, arr2)) // [4,4,2]
const obj1 = {
foo: "bar",
baz: [
1, 2, 3
],
qux: {
hello: "world"
},
bingo: "name-o",
}
const obj2 = {
foo: "barx",
baz: [
1, 2, 3, 4
],
qux: {
hello: null
},
bingo: "name-o",
}
console.log(getChanges(obj1.foo, obj2.foo)) // barx
console.log(getChanges(obj1.bingo, obj2.bingo)) // ""
console.log(getChanges(obj1.baz, obj2.baz)) // [4]
console.log(getChanges(obj1, obj2)) // {foo:'barx',baz:[1,2,3,4],qux:{hello:null}}
const obj3 = [{ name: 'test01', age: 10 }, { name: 'test02', age: 20 }, { name: 'test03', age: 30 }]
const obj4 = [{ name: 'test01', age: 10 }, { name: 'test02', age: 20 }, { name: 'test03', age: 20 }]
console.log(getChanges(obj3, obj4)) // [{name:'test03', age:20}]
Utility functions used:
// not required for this example but aid readability of the main function
const typeOf = o => Object.prototype.toString.call(o);
const isObject = o => o !== null && !Array.isArray(o) && typeOf(o).split(" ")[1].slice(0, -1) === "Object";
const isPrimitive = o => {
switch (typeof o) {
case "object": {
return false;
}
case "function": {
return false;
}
default: {
return true;
}
}
};
You would simply have to export the full list of edited values client side, compare it with the old list, and then send the list of changes off to the server.
Hope this helps!
Here are a few ideas.
Use a framework. You spoke of Angular.
Use Proxies, though Internet Explorer has no support for it.
Instead of using classic properties, maybe use Object.defineProperty's set/get to achieve some kind of change tracking.
Use getter/setting functions to store data instead of properties: getName() and setName() for example. Though this the older way of doing what defineProperty now does.
Whenever you bind your data to your form elements, set a special property that indicates if the property has changed. Something like __hasChanged. Set to true if any property on the object changes.
The old school bruteforce way: keep your original list of data that came from the server, deep copy it into another list, bind your form controls to the new list, then when the user clicks submit, compare the objects in the original list to the objects in the new list, plucking out the changed ones as you go. Probably the easiest, but not necessarily the cleanest.
A different take on #6: Attach a special property to each object that always returns the original version of the object:
var myData = [{name: "Larry", age: 47}];
var dataWithCopyOfSelf = myData.map(function(data) {
Object.assign({}, data, { original: data });
});
// now bind your form to dataWithCopyOfSelf.
Of course, this solution assumes a few things: (1) that your objects are flat and simple since Object.assign() doesn't deep copy, (2) that your original data set will never be changed, and (3) that nothing ever touches the contents of original.
There are a multitude of solutions out there.
With ES6 we can use Proxy
to accomplish this task: intercept an Object write, and mark it as dirty.
Proxy allows to create a handler Object that can trap, manipulate, and than forward changes to the original target Object, basically allowing to reconfigure its behavior.
The trap we're going to adopt to intercept Object writes is the handler set().
At this point we can add a non-enumerable property flag like i.e: _isDirty using Object.defineProperty() to mark our Object as modified, dirty.
When using traps (in our case the handler's set()) no changes are applied nor reflected to the Objects, therefore we need to forward the argument values to the target Object using Reflect.set().
Finally, to retrieve the modified objects, filter() the Array with our proxy Objects in search of those having its own Property "_isDirty".
// From server:
const dataOrg = [
{id:1, name:'a', age:10},
{id:2, name:'b', age:20},
{id:3, name:'c', age:30}
];
// Mirror data from server to observable Proxies:
const data = dataOrg.map(ob => new Proxy(ob, {
set() {
Object.defineProperty(ob, "_isDirty", {value: true}); // Flag
return Reflect.set(...arguments); // Forward trapped args to ob
}
}));
// From now on, use proxied data. Let's change some values:
data[0].name = "Lorem";
data[0].age = 42;
data[2].age = 31;
// Collect modified data
const dataMod = data.filter(ob => ob.hasOwnProperty("_isDirty"));
// Test what we're about to send back to server:
console.log(JSON.stringify(dataMod, null, 2));
Without using .defineProperty()
If for some reason you don't feel comfortable into tapping into the original object adding extra properties as flags, you could instead populate immediately
the dataMod (array with modified Objects) with references:
const dataOrg = [
{id:1, name:'a', age:10},
{id:2, name:'b', age:20},
{id:3, name:'c', age:30}
];
// Prepare array to hold references to the modified Objects
const dataMod = [];
const data = dataOrg.map(ob => new Proxy(ob, {
set() {
if (dataMod.indexOf(ob) < 0) dataMod.push(ob); // Push reference
return Reflect.set(...arguments);
}
}));
data[0].name = "Lorem";
data[0].age = 42;
data[2].age = 31;
console.log(JSON.stringify(dataMod, null, 2));
Can I Use - Proxy (IE)
Proxy - handler.set()
Global Objects - Reflect
Reflect.set()
Object.defineProperty()
Object.hasOwnProperty()
Without having to get fancy with prototype properties you could simply store them in another array whenever your form control element detects a change
Something along the lines of:
var modified = [];
data.forEach(function(item){
var domNode = // whatever you use to match data to form control element
domNode.addEventListener('input',function(){
if(modified.indexOf(item) === -1){
modified.push(item);
}
});
});
Then send the modified array to server when it's time to save
Why not use Ember.js observable properties ? You can use the Ember.observer function to get and set changes in your data.
Ember.Object.extend({
valueObserver: Ember.observer('value', function(sender, key, value, rev) {
// Executes whenever the "value" property changes
// See the addObserver method for more information about the callback arguments
})
});
The Ember.object actually does a lot of heavy lifting for you.
Once you define your object, add an observer like so:
object.addObserver('propertyKey', targetObject, targetAction)
My idea is to sort object keys and convert object to be string to compare:
// use this function to sort keys, and save key=>value in an array
function objectSerilize(obj) {
let keys = Object.keys(obj)
let results = []
keys.sort((a, b) => a > b ? -1 : a < b ? 1 : 0)
keys.forEach(key => {
let value = obj[key]
if (typeof value === 'object') {
value = objectSerilize(value)
}
results.push({
key,
value,
})
})
return results
}
// use this function to compare
function compareObject(a, b) {
let aStr = JSON.stringify(objectSerilize(a))
let bStr = JSON.stringify(objectSerilize(b))
return aStr === bStr
}
This is what I think up.
It would be cleanest, I’d think to have the object emit an event when a property is added or removed or modified.
A simplistic implementation could involve an array with the object keys; whenever a setter or heck the constructor returns this, it first calls a static function returning a promise; resolving: map with changed values in the array: things added, things removed, or neither. So one could get(‘changed’) or so forth; returning an array.
Similarly every setter can emit an event with arguments for initial value and new value.
Assuming classes are used, you could easily have a static method in a parent generic class that can be called through its constructor and so really you could simplify most of this by passing the object either to itself, or to the parent through super(checkMeProperty).