Why does updating properties in one object change another object? - javascript

I'm loading JSON data into an object via ajax, copying that object to new objects (initData and newData). When I change the property of newData, the property of initData also changes. Why is this happening?
var initData = {};
var newData = {};
function load_data(NDB_No){
$.getJSON(('scripts/jsonencode.php?q=' + NDB_No), function(data) {
for (prop in data){
initData[prop] = data[prop];
newData[prop] = data[prop];
}
console.log('init data: ' + initData.properties.Protein); // "init data: 0.259"
console.log('new data: ' + newData.properties.Protein); // "new data: 0.259"
var n = parseFloat(newData.properties.Protein);
newData.properties.Protein = n+1;
console.log('init data: ' + initData.properties.Protein + 'new data: ' + newData.properties.Protein);
// "init data: 1.259 new data: 1.259"
// why are these the same when I only updated newData object?
});
}

It looks like data[prop] is an object (since you are later referring to newData.properties.Protein). Objects are always passed by reference, with the variable just being a pointer to it.
Since you're getting JSON in the first place, your object is JSON-able, so you can use that to "clone" the object:
$.getJSON(...,function(data) {
initData = JSON.parse(JSON.stringify(data));
newData = JSON.parse(JSON.stringify(data));
});
This will ensure that the objects are separate. There are other ways to do this, but this one avoids the manual recursion by using built-in methods (always faster)

This sets both to reference the same memory space:
initData[prop] = data[prop];
newData[prop] = data[prop];
...so when you change newData, you also change initData. Instead of assigning by reference, you'll want to create a copy. I have to run, so I can't provide an example of that right now.

Related

getting all locally defined objects in javascript module

I have this code:
<script type="module">
const _Tasks = {};
const _client = {};
const _client_simple = {};
const _status = {};
const _status_simple = {};
//need here a function to get all above declared and defined objects in a loop
</script>
I am trying to get all the above declared and defined objects in a loop.
I have tried this way:
const objects = Object.getOwnPropertyNames(this);
objects.forEach(objectName => {
console.log(objectName);
});
But this is undefined.
Is this possible and how?
JavaScript provides no mechanisms for determining what variables exist.
If you need to programmatically inspect a group of data, then you need to express that data as a group in the first place (e.g. as properties of an object that you can iterate through) instead of as individual variables.
If, on the other hand, this is just for debugging purposes, then pausing execution in the module (e.g. with a breakpoint) will cause most debugging tools to display the variables in scope.
Short answer: JavaScript has no concept of querying the list of variables defined as const or let.
You can however query the list of variables defined with var because they are attached to the window object. This is the windowKeys example below.
If you want to query the variables why not adding them to an object? This is the myObjectKeys example below.
var _Tasks = {};
var _client = {};
var _client_simple = {};
var _a_number = 123;
var _a_string = "hello";
var _a_boolean = true;
const windowKeys = Object.keys(window).filter(key => /^_/.test(key));
console.log('windowKeys:');
windowKeys.forEach(key => {
console.log(' ' + key + ', type: ' + typeof window[key]);
});
const myObject = {
_Tasks: {},
_client: {},
_client_simple: {},
_a_number: 123,
_a_string: "hello",
_a_boolean: true
}
const myObjectKeys = Object.keys(myObject);
console.log('myObjectKeys:');
windowKeys.forEach(key => {
console.log(' ' + key + ', type: ' + typeof myObject[key]);
});
Output:
windowKeys:
_Tasks, type: object
_client, type: object
_client_simple, type: object
_a_number, type: number
_a_string, type: string
_a_boolean, type: boolean
myObjectKeys:
_Tasks, type: object
_client, type: object
_client_simple, type: object
_a_number, type: number
_a_string, type: string
_a_boolean, type: boolean

how can i filtering data from Firebase rt-db using javascript

I need to print in console value of key temp but no things displayed
var database=firebase.database();
var ratingRef = firebase.database().ref("sensors/temp/");
ratingRef.orderByValue().on("value", function(data) {
data.forEach(function(data) {
console.log( data.val());
});
});
There's no need for using orderByValue. You have direct reference to the temp child so the data (which is a DataSnapshot) contain the value of temp only.
var ratingRef = firebase.database().ref("sensors/temp");
ratingRef.on("value", function(data) {
console.log(`Temp: ${data.val()}`)
});

Merge dynamic object arrays in javascript

I'm trying to dynamically build an object with key:[value array], however using different methods I keep ending up with a singular item in the value array (where in the response there are multiple values).
Psuedocode:
var myFunction = function () {
var myObject = {};
$.ajax('http://the.url.com', {
type: "GET",
success: function (res) {
$(res).each(function (i, v) {
var name = v.name;
var id = v.id;
// create object with building block and tech id to associate techs to BBs
myObject[name] = new Array();
myObject[name].push(id);
});
},
error: function (xhr) {}
}
}
Current output:
{
key1: ["value1c"]
key2: ["value2a"]
key3: ["value3b"]
}
Desired output:
{
key1: ["value1a", "value1b","value1c"]
key2: ["value2a"]
key3: ["value3a", "value3b"]
}
You're overwriting the existing array with a new one for each key, then pushing the latest one in with the following line:
myObject[name] = new Array();
Try adding a check to avoid overwriting:
myObject[name] = myObject[name] || new Array();
The out put is key1: ["value1c"] since key in an object is unique, so it is creating key and storing only latest value. You can use hasOwnProperty and check if myObject has any key by that name. If so then push the value, else create a key value pair and add id to it
$(res).each(function(i, v) {
var name = v.name;
var id = v.id;
if (myObject.hasOwnProperty(name)) {
myObject[name].push(id);
} else {
myObject[name] = [id];
}
});
I think that you need to check if myObject[name] already exists before creating a new one. Because if you create a new one each time, it will be overridden
var myFunction = function () {
var myObject = {};
$.ajax('http://the.url.com', {
type: "GET",
success: function (res) {
$(res).each(function (i, v) {
var name = v.name;
var id = v.id;
// create object with building block and tech id to associate techs to BBs
if (!myObject[name]) {
myObject[name] = new Array();
}
myObject[name].push(id);
});
},
error: function (xhr) {}
}
}
You create another array each time with this line :
myObject[name] = new Array();
So you delete the old pushed value each time.
Use a condition to initialize your array if not exist :
!Array.isArray(myObject[name]) && (myObject[name] = new Array());
e.g.
$(res).each(function(i, v) {
var name = v.name;
var id = v.id;
// create object with building block and tech id to associate techs to BBs
!Array.isArray(myObject[name]) && (myObject[name] = new Array());
myObject[name].push(id);
});

How to make a copy of a Parse Object in the Cloud?

I would like to have a copy if an existing Parse Object, and then make some edits and save it as a new Parse Object rather than setting each field manually.
Here is my cloud function :
Parse.Cloud.define("SharePost", function(request, response) {
var ShareUserID=request.params.ShareUserID;
var UserID=request.params.UserID;
var PostID=request.params.PostID;
Parse.Cloud.useMasterKey();
var user = new Parse.User({id:UserID});
var shareuser = new Parse.User({id:ShareUserID});
var query = new Parse.Query("Feed");
query.get(PostID, {
success: function(post) {
var Post = Parse.Object.extend("Feed");
var newpost = new Post()
// here I would like to get the same object and make some edits o, it
post.save( {
success:function () {
response.success("Success");
},
error:function (pointAward, error) {
response.success(error);
}
}
);
},
error: function(error) {
console.error("Got an error " + error.code + " : " + error.message);
}
});
});
There might be a prettier way, but one way that's sure to work without relying on any subtleties would be this:
function pfClone(fromObject, toObject, keys) {
var _ = require('underscore');
_.each(keys, function(key) {
toObject.set(key, fromObject.get(key));
});
}
call it like this:
// after fetching a post called "post"
var Post = Parse.Object.extend("Feed");
var newpost = new Post();
var keys = ["title", "author" /* ...the keys you want to copy unchanged */ ];
pfClone(post, newpost, keys);
// change other properties of newpost here
Even prettier would be a version that introspects on the passed object, and then builds and initializes the clone. The one inelegance for either of these ideas is that (last time I checked) PFObject doesn't let you introspect the keys, so you're stuck passing in an array of keys.

Is there a Jquery function that can take a #ref id value from a parsed JSON string and point me to the referenced object?

I have been looking for an answer to this all afternoon and i cant seem to find the best way to accomplish what i need to.
My JSON string (returned from a web service) has circular references in it (#ref) which point to $id in the string. Now i know that if use jquery parseJSON it creates the javascript object and i can access properties a la myObject.MyPropertyName. However, when i get to a #ref, i am unsure how to get the object that ID points to (which i assume is already created as a result of the de-serialization...
Should i be iterating though the object and all its child objects until i find it, or is there an easier way?
$.ajax({
type: "POST",
url: "/Task.asmx/GetTask",
data: "{'id':'" + '27' + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
_Data = $.parseJSON(msg.d ? msg.d : msg);
_this.Company = _Data[0].t_Program.t_Company;
_this.Program = _Data[0].t_Program;
_this.Task = _Data[0];
},
complete: function () {
}
});
The area in question is _Data[0].t_Program because it does not return an object but rather returns
_Data[0].t_Program
{...}
$ref: "12"
I dont exactly know the best way to get the object with $id "12". Based on the posts below it seems i should loop through the existing object, but i was hoping there was a jquery function that did that...
Many Thanks!
No, jQuery is not natively capable of resolving circular references in objects converted from JSON.
The only library for that which I know is Dojo's dojox.json.ref module.
But, your server application serializes that JSON somehow. Don't tell me that the solution it uses does not offer a deserialisation algorithm!
As my friend Alan, the author of the Xerox Courier (RPC over the net) library, used to say to me, "there are no pointers on the wire."
In other words, it is impossible for a JSON representation of a data structure to be circular. (But a circular structure can be flattened into a non-circular JSON structure.) As the JSON site says:
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
No pointers!
So the entire JSON will have been turned into Javascript Objects and/or Arrays after the jQuery parseJSON operation completes.
If the original stucture's ref_id values were used as the property names in the JSON / Javascript object, then they'll all be there.
The real issue is that you need to understand how your server serialized its data structure into the JSON data structure. Look in your server-side code to determine that.
Then use Javascript to de-serialize the JSON structure back into the best Javascript structure to fit your needs.
Re: Should i be iterating though the object and all its child objects until i find it, or is there an easier way?
The easier way would be to go through the Javascript structure once, and build up an additional "indexing" object whose properties are the #ref_id and the values are the original structure/value.
Sample:
var jsonCyclicReferenceFixed = JsonRecursive.parse(jsonWithRefAndId);
(function(){
function type(value){
var t = typeof(value);
if( t == "object" && value instanceof Array) {
return "array";
}
if( t == "object" && value && "$id" in value && "$values" in value) {
return "array";
}
return t;
}
function TypeConverterFactory(){
var converters = {};
var defaultConverter = {
fromJson: function(value){ return value; },
toJson: function(value){ return value; },
};
this.create = function(type){
var converter = converters[type];
if(!converter) return defaultConverter;
return converter;
};
this.register = function(type, converter){
converters[type] = converter;
converter.valueConverter = this.valueConverter;
};
}
function ObjectConverter(){
this.fromJson = function(obj){
if( obj == null ) return null;
if( "$ref" in obj ){
var reference = this.dictionary[obj.$ref];
return reference;
}
if("$id" in obj){
this.dictionary[obj.$id] = obj;
delete obj.$id;
}
for(var prop in obj){
obj[prop] = this.valueConverter.convertFromJson(obj[prop]);
}
return obj;
}
this.toJson = function(obj){
var id = 0;
if(~(id = this.dictionary.indexOf(obj))){
return { "$ref" : (id + 1).toString() };
}
var convertedObj = { "$id" : this.dictionary.push(obj).toString() };
for(var prop in obj){
convertedObj[prop] = this.valueConverter.convertToJson(obj[prop]);
}
return convertedObj;
}
}
function ArrayConverter(){
var self = this;
this.fromJson = function(arr){
if( arr == null ) return null;
if("$id" in arr){
var values = arr.$values.map(function(item){
return self.valueConverter.convertFromJson(item);
});
this.dictionary[arr.$id] = values;
delete arr.$id;
return values;
}
return arr;
}
this.toJson = function(arr){
var id = 0;
if(~(id = this.dictionary.indexOf(arr))){
return { "$ref" : (id + 1).toString() };
}
var convertedObj = { "$id" : this.dictionary.push(arr).toString() };
convertedObj.$values = arr.map(function(arrItem){
return self.valueConverter.convertToJson(arrItem);
});
return convertedObj;
}
}
function ValueConverter(){
this.typeConverterFactory = new TypeConverterFactory();
this.typeConverterFactory.valueConverter = this;
this.typeConverterFactory.register("array", new ArrayConverter);
this.typeConverterFactory.register("object", new ObjectConverter);
this.dictionary = {};
this.convertToJson = function(valor){
var converter = this.typeConverterFactory.create(type(valor));
converter.dictionary = this.dictionary;
return converter.toJson(valor);
}
this.convertFromJson = function(valor){
var converter = this.typeConverterFactory.create(type(valor));
converter.dictionary = this.dictionary;
return converter.fromJson(valor);
}
}
function JsonRecursive(){
this.valueConverter = new ValueConverter();
}
JsonRecursive.prototype.convert = function(obj){
this.valueConverter.dictionary = [];
var converted = this.valueConverter.convertToJson(obj);
return converted;
}
JsonRecursive.prototype.parse = function(string){
this.valueConverter.dictionary = {};
var referenced = JSON.parse(string);
return this.valueConverter.convertFromJson(referenced);
}
JsonRecursive.prototype.stringify = function(obj){
var converted = this.convert(obj);
var params = [].slice.call(arguments, 1);
return JSON.stringify.apply(JSON, [converted].concat(params));
}
if(window){
if( window.define ){
//to AMD (require.js)
window.define(function(){
return new JsonRecursive();
});
}else{
//basic exposition
window.jsonRecursive = new JsonRecursive();
}
return;
}
if(global){
// export to node.js
module.exports = new JsonRecursive();
}
}());
Sample:
// a object recursive
// var parent = {};
// var child = {};
// parent.child = child;
// child.parent = parent;
//
//results in this recursive json
var json = '{"$id":"0","name":"Parent","child":{"$id":"1","name":"Child","parent":{"$ref":"0"}}}'
//Parsing a Recursive Json to Object with references
var obj = jsonRecursive.parse(json);
// to see results try console.log( obj );
alert(obj.name);
alert(obj.child.name);

Categories

Resources