What I'd like to do
describe('my object', function() {
it('has these properties', function() {
expect(Object.keys(myObject)).toEqual([
'property1',
'property2',
...
]);
});
});
but of course Object.keys returns an array, which by definition is ordered...I'd prefer to have this test pass regardless of property ordering (which makes sense to me since there is no spec for object key ordering anyway...(at least up to ES5)).
How can I verify my object has all the properties it is supposed to have, while also making sure it isn't missing any properties, without having to worry about listing those properties in the right order?
It's built in now!
describe("jasmine.objectContaining", function() {
var foo;
beforeEach(function() {
foo = {
a: 1,
b: 2,
bar: "baz"
};
});
it("matches objects with the expect key/value pairs", function() {
expect(foo).toEqual(jasmine.objectContaining({
bar: "baz"
}));
expect(foo).not.toEqual(jasmine.objectContaining({
c: 37
}));
});
});
Alternatively, you could use external checks like _.has (which wraps myObject.hasOwnProperty(prop)):
var _ = require('underscore');
describe('my object', function() {
it('has these properties', function() {
var props = [
'property1',
'property2',
...
];
props.forEach(function(prop){
expect(_.has(myObject, prop)).toBeTruthy();
})
});
});
The simplest solution? Sort.
var actual = Object.keys(myObject).sort();
var expected = [
'property1',
'property2',
...
].sort();
expect(actual).toEqual(expected);
it('should contain object keys', () => {
expect(Object.keys(myObject)).toContain('property1');
expect(Object.keys(myObject)).toContain('property2');
expect(Object.keys(myObject)).toContain('...');
});
I ended up here because I was looking for a way to check that an object had a particular subset of properties.
I started with _.has or Object.hasOwnProperties but the output of Expected false to be truthy when it failed wasn't very useful.
Using underscore's intersection gave me a better expected/actual output
var actualProps = Object.keys(myObj); // ["foo", "baz"]
var expectedProps =["foo","bar"];
expect(_.intersection(actualProps, expectedProps)).toEqual(expectedProps);
In which case a failure might look more like
Expected [ 'foo' ] to equal [ 'foo', 'bar' ]
Here are some new possible solutions too:
There's a module for that: https://www.npmjs.com/package/jasmine-object-matchers
With ES2016, you can use a map and convert the object to a map too
I prefer use this; becouse, you have more possibilities to be execute indivual test.
import AuthRoutes from '#/router/auth/Auth.ts';
describe('AuthRoutes', () => {
it('Verify that AuthRoutes be an object', () => {
expect(AuthRoutes instanceof Object).toBe(true);
});
it("Verify that authroutes in key 'comecios' contains expected key", () => {
expect(Object.keys(AuthRoutes.comercios)).toContain("path");
expect(Object.keys(AuthRoutes.comercios)).toContain("component");
expect(Object.keys(AuthRoutes.comercios)).toContain("children");
expect(AuthRoutes.comercios.children instanceof Array).toBe(true);
// Convert the children Array to Object for verify if this contains the spected key
let childrenCommerce = Object.assign({}, AuthRoutes.comercios.children);
expect(Object.keys(childrenCommerce[0])).toContain("path");
expect(Object.keys(childrenCommerce[0])).toContain("name");
expect(Object.keys(childrenCommerce[0])).toContain("component");
expect(Object.keys(childrenCommerce[0])).toContain("meta");
expect(childrenCommerce[0].meta instanceof Object).toBe(true);
expect(Object.keys(childrenCommerce[0].meta)).toContain("Auth");
expect(Object.keys(childrenCommerce[0].meta)).toContain("title");
})
});
I am late to this topic but there is a a method that allows you to check if an object has a property or key/value pair:
expect(myObject).toHaveProperty(key);
expect({"a": 1, "b":2}).toHaveProperty("a");
or
expect(myObject).toHaveProperty(key,value);
expect({"a": 1, "b":2}).toHaveProperty("a", "1");
Related
Is there a way to set the default attribute of a Javascript object such that:
let emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue
Since I asked the question several years ago things have progressed nicely.
Proxies are part of ES6. The following example works in Chrome, Firefox, Safari and Edge:
let handler = {
get: function(target, name) {
return target.hasOwnProperty(name) ? target[name] : 42;
}
};
let emptyObj = {};
let p = new Proxy(emptyObj, handler);
p.answerToTheUltimateQuestionOfLife; //=> 42
Read more in Mozilla's documentation on Proxies.
Use destructuring (new in ES6)
There is great documentation by Mozila as well as a fantastic blog post that explains the syntax better than I can.
To Answer Your Question
var emptyObj = {};
const { nonExistingAttribute = defaultValue } = emptyObj;
console.log(nonExistingAttribute); // defaultValue
Going Further
Can I rename this variable? Sure!
const { nonExistingAttribute: coolerName = 15} = emptyObj;
console.log(coolerName); // 15
What about nested data? Bring it on!
var nestedData = {
name: 'Awesome Programmer',
languages: [
{
name: 'javascript',
proficiency: 4,
}
],
country: 'Canada',
};
var {name: realName, languages: [{name: languageName}]} = nestedData ;
console.log(realName); // Awesome Programmer
console.log(languageName); // javascript
There isn't a way to set this in Javascript - returning undefined for non-existent properties is a part of the core Javascript spec. See the discussion for this similar question. As I suggested there, one approach (though I can't really recommend it) would be to define a global getProperty function:
function getProperty(o, prop) {
if (o[prop] !== undefined) return o[prop];
else return "my default";
}
var o = {
foo: 1
};
getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // "my default"
But this would lead to a bunch of non-standard code that would be difficult for others to read, and it might have unintended consequences in areas where you'd expect or want an undefined value. Better to just check as you go:
var someVar = o.someVar || "my default";
my code is:
function(s){
s = {
top: s.top || 100, // default value or s.top
left: s.left || 300, // default value or s.left
}
alert(s.top)
}
The way I achieve this is with the object.assign function
const defaultProperties = { 'foo': 'bar', 'bar': 'foo' };
const overwriteProperties = { 'foo': 'foo' };
const newObj = Object.assign({}, defaultProperties, overwriteProperties);
console.log(defaultProperties); // {"foo": "bar", "bar": "foo"}
console.log(overwriteProperties); // { "foo": "foo" };
console.log(newObj); // { "foo": "foo", "bar": "foo" }
This seems to me the most simple and readable way of doing so:
let options = {name:"James"}
const default_options = {name:"John", surname:"Doe"}
options = Object.assign({}, default_options, options)
Object.assign() reference
This sure sounds like the typical use of protoype-based objects:
// define a new type of object
var foo = function() {};
// define a default attribute and value that all objects of this type will have
foo.prototype.attribute1 = "defaultValue1";
// create a new object of my type
var emptyObj = new foo();
console.log(emptyObj.attribute1); // outputs defaultValue1
I think the simplest approach is using Object.assign.
If you have this Class:
class MyHelper {
constructor(options) {
this.options = Object.assign({
name: "John",
surname: "Doe",
birthDate: "1980-08-08"
}, options);
}
}
You can use it like this:
let helper = new MyHelper({ name: "Mark" });
console.log(helper.options.surname); // this will output "Doe"
Documentation (with polyfill):
https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Or you can try this
dict = {
'somekey': 'somevalue'
};
val = dict['anotherkey'] || 'anotherval';
Simplest of all Solutions:
dict = {'first': 1,
'second': 2,
'third': 3}
Now,
dict['last'] || 'Excluded'
will return 'Excluded', which is the default value.
If you only have an object that is a single level deep (nested object properties will not merge as expected since it directly destructures from the first level), you can use the following destructuring syntax:
const options = {
somevar: 1234,
admin: true
};
const defaults = {
test: false,
admin: false,
};
var mergedOptions = {...defaults, ...options};
Of which the output would be:
console.log(options);
// { somevar: 1234, admin: true }
console.log(mergedOptions);
// { test: false, admin: true, somevar: 1234 }
Or even formatted as a single statement (this is slightly unreadable though):
const options = {...{
// Defaults
test: false,
admin: false,
}, ...{
// Overrides
somevar: 1234,
admin: true
}};
I saw an article yesterday that mentions an Object.__noSuchMethod__ property: JavascriptTips I've not had a chance to play around with it, so I don't know about browser support, but maybe you could use that in some way?
I'm surprised nobody has mentioned ternary operator yet.
var emptyObj = {a:'123', b:'234', c:0};
var defaultValue = 'defaultValue';
var attr = 'someNonExistAttribute';
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue'
attr = 'c'; // => 'c'
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0
In this way, even if the value of 'c' is 0, it will still get the correct value.
var obj = {
a: 2,
b: 4
};
console.log(obj);
--> {a: 2, b: 4}
function applyDefaults(obj) {
obj.a ||= 10;
obj.b ||= 10;
obj.c ||= 10;
}
// do some magic
applyDefaults(obj);
console.log(obj);
--> {a: 2, b: 4, c: 10}
This works because
undefined || "1111111" --> "1111111"
"0000000" || "1111111" --> "0000000"
as null, undefined, NaN, 0, "" (Empty String), false itself, are all considered to be equivalent to false (falsy). Anything else is true (truthy).
Note that this is not uniformly supported across browsers and nodejs versions (confirm for yourself).
So two troublesome cases are the empty String "" and 0 (zero). If it is important not to override those, you might need to rewrite this as:
if (typeof obj.d == "undefined") obj.d = "default"
This will be better supported across browsers also.
Alternatively you could write this as:
obj.d ??= "default"
This is the nullish assignment which applies only to values that are null or undefined (nullish) - of which the empty string is not part. However, this has again a diminished cross-browser support.
See also on the official Mozilla Website - Assigning a default value to a variable.
This is actually possible to do with Object.create. It will not work for "non defined" properties. But for the ones that has been given a default value.
var defaults = {
a: 'test1',
b: 'test2'
};
Then when you create your properties object you do it with Object.create
properties = Object.create(defaults);
Now you will have two object where the first object is empty, but the prototype points to the defaults object. To test:
console.log('Unchanged', properties);
properties.a = 'updated';
console.log('Updated', properties);
console.log('Defaults', Object.getPrototypeOf(properties));
Object.withDefault = (defaultValue,o={}) => {
return new Proxy(o, {
get: (o, k) => (k in o) ? o[k] : defaultValue
});
}
o = Object.withDefault(42);
o.x //=> 42
o.x = 10
o.x //=> 10
o.xx //=> 42
One approach would be to take a defaults object and merge it with the target object. The target object would override values in the defaults object.
jQuery has the .extend() method that does this. jQuery is not needed however as there are vanilla JS implementations such as can be found here:
http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
With the addition of the Logical nullish assignment operator, you can now do something like this
const obj = {}
obj.a ??= "default";
In the case where you have an empty list as the default value and want to push to it, you could do
const obj = {}
(obj.a ??= []).push("some value")
I came here looking for a solution because the header matched my problem description but it isn't what i was looking for but i got a solution to my problem(I wanted to have a default value for an attribute which would be dynamic something like date).
let Blog = {
title : String,
image : String,
body : String,
created: {type: Date, default: Date.now}
}
The above code was the solution for which i finally settled.
Is there a way to set the default attribute of a Javascript object such that:
let emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue
Since I asked the question several years ago things have progressed nicely.
Proxies are part of ES6. The following example works in Chrome, Firefox, Safari and Edge:
let handler = {
get: function(target, name) {
return target.hasOwnProperty(name) ? target[name] : 42;
}
};
let emptyObj = {};
let p = new Proxy(emptyObj, handler);
p.answerToTheUltimateQuestionOfLife; //=> 42
Read more in Mozilla's documentation on Proxies.
Use destructuring (new in ES6)
There is great documentation by Mozila as well as a fantastic blog post that explains the syntax better than I can.
To Answer Your Question
var emptyObj = {};
const { nonExistingAttribute = defaultValue } = emptyObj;
console.log(nonExistingAttribute); // defaultValue
Going Further
Can I rename this variable? Sure!
const { nonExistingAttribute: coolerName = 15} = emptyObj;
console.log(coolerName); // 15
What about nested data? Bring it on!
var nestedData = {
name: 'Awesome Programmer',
languages: [
{
name: 'javascript',
proficiency: 4,
}
],
country: 'Canada',
};
var {name: realName, languages: [{name: languageName}]} = nestedData ;
console.log(realName); // Awesome Programmer
console.log(languageName); // javascript
There isn't a way to set this in Javascript - returning undefined for non-existent properties is a part of the core Javascript spec. See the discussion for this similar question. As I suggested there, one approach (though I can't really recommend it) would be to define a global getProperty function:
function getProperty(o, prop) {
if (o[prop] !== undefined) return o[prop];
else return "my default";
}
var o = {
foo: 1
};
getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // "my default"
But this would lead to a bunch of non-standard code that would be difficult for others to read, and it might have unintended consequences in areas where you'd expect or want an undefined value. Better to just check as you go:
var someVar = o.someVar || "my default";
my code is:
function(s){
s = {
top: s.top || 100, // default value or s.top
left: s.left || 300, // default value or s.left
}
alert(s.top)
}
The way I achieve this is with the object.assign function
const defaultProperties = { 'foo': 'bar', 'bar': 'foo' };
const overwriteProperties = { 'foo': 'foo' };
const newObj = Object.assign({}, defaultProperties, overwriteProperties);
console.log(defaultProperties); // {"foo": "bar", "bar": "foo"}
console.log(overwriteProperties); // { "foo": "foo" };
console.log(newObj); // { "foo": "foo", "bar": "foo" }
This seems to me the most simple and readable way of doing so:
let options = {name:"James"}
const default_options = {name:"John", surname:"Doe"}
options = Object.assign({}, default_options, options)
Object.assign() reference
This sure sounds like the typical use of protoype-based objects:
// define a new type of object
var foo = function() {};
// define a default attribute and value that all objects of this type will have
foo.prototype.attribute1 = "defaultValue1";
// create a new object of my type
var emptyObj = new foo();
console.log(emptyObj.attribute1); // outputs defaultValue1
I think the simplest approach is using Object.assign.
If you have this Class:
class MyHelper {
constructor(options) {
this.options = Object.assign({
name: "John",
surname: "Doe",
birthDate: "1980-08-08"
}, options);
}
}
You can use it like this:
let helper = new MyHelper({ name: "Mark" });
console.log(helper.options.surname); // this will output "Doe"
Documentation (with polyfill):
https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Or you can try this
dict = {
'somekey': 'somevalue'
};
val = dict['anotherkey'] || 'anotherval';
Simplest of all Solutions:
dict = {'first': 1,
'second': 2,
'third': 3}
Now,
dict['last'] || 'Excluded'
will return 'Excluded', which is the default value.
If you only have an object that is a single level deep (nested object properties will not merge as expected since it directly destructures from the first level), you can use the following destructuring syntax:
const options = {
somevar: 1234,
admin: true
};
const defaults = {
test: false,
admin: false,
};
var mergedOptions = {...defaults, ...options};
Of which the output would be:
console.log(options);
// { somevar: 1234, admin: true }
console.log(mergedOptions);
// { test: false, admin: true, somevar: 1234 }
Or even formatted as a single statement (this is slightly unreadable though):
const options = {...{
// Defaults
test: false,
admin: false,
}, ...{
// Overrides
somevar: 1234,
admin: true
}};
I saw an article yesterday that mentions an Object.__noSuchMethod__ property: JavascriptTips I've not had a chance to play around with it, so I don't know about browser support, but maybe you could use that in some way?
I'm surprised nobody has mentioned ternary operator yet.
var emptyObj = {a:'123', b:'234', c:0};
var defaultValue = 'defaultValue';
var attr = 'someNonExistAttribute';
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue'
attr = 'c'; // => 'c'
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0
In this way, even if the value of 'c' is 0, it will still get the correct value.
var obj = {
a: 2,
b: 4
};
console.log(obj);
--> {a: 2, b: 4}
function applyDefaults(obj) {
obj.a ||= 10;
obj.b ||= 10;
obj.c ||= 10;
}
// do some magic
applyDefaults(obj);
console.log(obj);
--> {a: 2, b: 4, c: 10}
This works because
undefined || "1111111" --> "1111111"
"0000000" || "1111111" --> "0000000"
as null, undefined, NaN, 0, "" (Empty String), false itself, are all considered to be equivalent to false (falsy). Anything else is true (truthy).
Note that this is not uniformly supported across browsers and nodejs versions (confirm for yourself).
So two troublesome cases are the empty String "" and 0 (zero). If it is important not to override those, you might need to rewrite this as:
if (typeof obj.d == "undefined") obj.d = "default"
This will be better supported across browsers also.
Alternatively you could write this as:
obj.d ??= "default"
This is the nullish assignment which applies only to values that are null or undefined (nullish) - of which the empty string is not part. However, this has again a diminished cross-browser support.
See also on the official Mozilla Website - Assigning a default value to a variable.
This is actually possible to do with Object.create. It will not work for "non defined" properties. But for the ones that has been given a default value.
var defaults = {
a: 'test1',
b: 'test2'
};
Then when you create your properties object you do it with Object.create
properties = Object.create(defaults);
Now you will have two object where the first object is empty, but the prototype points to the defaults object. To test:
console.log('Unchanged', properties);
properties.a = 'updated';
console.log('Updated', properties);
console.log('Defaults', Object.getPrototypeOf(properties));
Object.withDefault = (defaultValue,o={}) => {
return new Proxy(o, {
get: (o, k) => (k in o) ? o[k] : defaultValue
});
}
o = Object.withDefault(42);
o.x //=> 42
o.x = 10
o.x //=> 10
o.xx //=> 42
One approach would be to take a defaults object and merge it with the target object. The target object would override values in the defaults object.
jQuery has the .extend() method that does this. jQuery is not needed however as there are vanilla JS implementations such as can be found here:
http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
With the addition of the Logical nullish assignment operator, you can now do something like this
const obj = {}
obj.a ??= "default";
In the case where you have an empty list as the default value and want to push to it, you could do
const obj = {}
(obj.a ??= []).push("some value")
I came here looking for a solution because the header matched my problem description but it isn't what i was looking for but i got a solution to my problem(I wanted to have a default value for an attribute which would be dynamic something like date).
let Blog = {
title : String,
image : String,
body : String,
created: {type: Date, default: Date.now}
}
The above code was the solution for which i finally settled.
I have the following function:
/**
* filters array down to the given allowed keys
* #param {Object} data
* #param {String[]} allowedKeys
*/
$scope.filterData = function(data, allowedKeys) {
return Object.keys(data)
.filter(function(key) {
return allowedKeys.includes(key);
})
.reduce(function(obj, key) {
obj[key] = data[key];
return obj;
}, {});
};
that I want to create a unit test for and so far I have the following:
describe('$scope.filterData', function() {
//params
var data = {
key1: "value1",
key2: "value2",
key3: "value3"
}
var allowedKeys = ["key1", "key2"];
//mockobject
var $Object = jasmine.createSpyObj('Object', ['keys', 'filter', 'reduce']);
it('should func', function() {
$Object.keys.and.returnValue($Object);
$Object.filter.and.returnValue($Object);
$Object.reduce.and.returnValue($Object);
$scope.filterData(data, allowedKeys);
expect(Object.filter).toHaveBeenCalled();
});
});
The issue that I am having, is that I am getting the following error:
TypeError: undefined is not a constructor (evaluating 'allowedKeys.includes(key)')
I do not understand, how to fix that error?
I don't if this solution could help you or not
When we write test case, especially test for functions, we tend to test the input and output value for the function.
And for me, I think we shouldn't touch the primitive function of Array, Object by calling jasmine mock.
If you want to know if your function is working properly in this case.
For example:
describe('$scope.filterData', function() {
//params
var data = {
key1: "value1",
key2: "value2",
key3: "value3"
}
var allowedKeys = ["key1", "key2"];
it('should return 2 key', function() {
var expected = {
key1: "value1",
key2: "value2",
}
var value = $scope.filterData(data, allowedKeys);
expect(JSON.stringify(value)).toEqual(JSON.stringify());
});
});
Of course we have to mock some functions sometimes, like when we have the http request and have to wait, or we have function from other places to use and want to mock them.
But in this case, your function is not really necessary for expect some function to be called, it's simply enough and don't depend on anything else.So best we should only focus on the input and output values of function
First of all, Object does not have a function filterand your jasmine.createSpyObj is literally useless. As #Luan Phan says in his answer, we usually tend to test the input and output value for the function. Javascript built-in functions do not need to be tested in our tests.
But, if you would like to know, for example, if Object.keys was called inside your function, here is an example
it('should func', function () {
spyOn(Object, 'keys').and.callThrough();
$scope.filterData(data, allowedKeys);
expect(Object.keys).toHaveBeenCalled();
});
The same can be done for the rest of the built-in functions used in filterData
it('should func', function () {
spyOn(Object, 'keys').and.callThrough();
spyOn(Array.prototype, 'filter').and.callThrough();
spyOn(Array.prototype, 'reduce').and.callThrough();
$scope.filterData(data, allowedKeys);
expect(Object.keys).toHaveBeenCalled();
expect(Array.prototype.filter).toHaveBeenCalled();
expect(Array.prototype.reduce).toHaveBeenCalled();
});
If you really need to mock what one of the built-in functions returns, here is an example
it('should func', function () {
const mockResult = {};
spyOn(Array.prototype, 'reduce').and.returnValue(mockResult);
const result = filterData(data, allowedKeys);
expect(result).toBe(mockResult);
});
Again, Javascript's built-in functions already have tests written in some other place, we don't need to test it in our test, our focus should be on the functions we write.
Hope it helps
I'm trying to send data (as an object) to a child process in Node.js, however, all of my regular expressions get lost in transfer.
var arguments = {
something: {
name: 'test',
age: 28,
active; true
},
otherThing: 'some string',
regex: /test/i,
regex2: new RegExp('test')
};
var child = cp.fork(path.join(__dirname, 'child.js'));
child.on('message', function (data) {
console.log(data);
});
child.send(arguments);
In the child.js file I have this at the top:
process.on('message', function () {
console.log(arguments); // This is where the data has changed
});
When the log is output from the child process the arguments object instead looks like this:
{
something: {
name: 'test',
age: 28,
active: true
},
otherThing: 'some string',
regex: {},
regex2: {}
}
So far unable to find anything elsewhere about why this may be happening, any ideas?
Because they are completely separate JavaScript processes, you can't send objects. When you pass an object, it gets serialized to JSON and parsed by the child. (See the docs.)
JSON does not support serializing regex objects. (Try putting JSON.stringify(/abc/) through your console -- you get back "{}".)
To include regexes in a JSON object, you can use the json-fn module. It supports serializing functions, dates, and regexes. (It was actually thanks to an issue i raised that they added regex support. :))
You could then do something like:
var JSONfn = require('json-fn');
var arguments = {
something: {
name: 'test',
age: 28,
active; true
},
otherThing: 'some string',
regex: /test/i,
regex2: new RegExp('test')
};
var child = cp.fork(path.join(__dirname, 'child.js'));
});
child.send(JSONfn.stringify(arguments));
and:
var JSONfn = require('json-fn');
process.on('message', function (data) {
console.log(JSONfn.parse(data))); // This is where the data has changed
});
You can store the regex as a string like
myRegex.string = "/test/";
myRegex.modif = "i";
Send it to child and then use it like
new RegExp(myRegex.string, myRegex.modif);
I tried json-fn but Date objects stringified are not reverted back to Date. This module JSON4Process stringifies the objects' properties of type Date, RegExp, Function, Set and Map while maintaining the object as a javascript object. You don't need to stringify the whole object if you're using fork, you can directly send it.
const { fork } = require('child_process');
const JSON4Process = require('json4process');
let obj = {
date: new Date(),
regex: new RegExp(/regex/g),
func: () => console.log('func')
}
obj = JSON4Process.stringifyProps(obj);
const child = fork('child.js');
child.send(obj);
And then parse the properties back in the other file:
process.on('message', data => {
let obj = JSON4Process.parseProps(data);
});
In case you need to use spawn or exec you can just use the default JSON.stringify over the modified object with json4process:
let newObj = JSON.stringify(JSON4Process.stringifyProps(obj));
let originalObj = JSON4Process.parseProps(JSON.parse(newObj));
This post is not the same as: Is there a tidy way to define a large watch collection for AngularJS?
My code is (service.js):
var MyJSON = {
array: [
{k:'v'},
{k:'v'},
{k:'v'}
],
info: {
k: 'v',
k2: 'v2'
},
last: 1398680914943 // Date.now()
}
$rootScope.$watchCollection(function () { return MyJSON; }, function (n, o) {
console.log('Change');
});
Detects changes when I work on the root object "MyJSON". Like this:
MyJSON.last = 123456789; // console: Change
But if I am doing something like this:
MyJSON.info.k = 'vDummie';
or:
MyJSON.array.push({k:'something'});
"$watchCollection" does not work.
$watchCollection watches only the 1st level properties; use $watch(..., ..., true) to do "deep" watching. Note: there are 3 arguments, the first two are the same as your code, the third is true for deep watch.