Knockout Mapping: JSON grows when mapping and saving multiple times - javascript

When I take a knockout object and serialize it to JSON by doing ko.toJSON, and then unserialize it from JSON using ko.mapping.fromJSON multiple times, the loaded object has this __ko_mapping__ property that recursively grows.
Sample code:
var joe = new Person();
for (var i = 0; i < 10; i++) {
var json = ko.toJSON(joe);
joe = ko.mapping.fromJSON(json);
}
Simple JSFiddle that reproduces it:
http://jsfiddle.net/Gc89Q/1/
How can I load and save multiple times without having the serialized json form grow to be gigantic?
I was considering just setting the __ko_mapping__ property to undefined when loading, but am wondering if there is a better way or something I am missing.
Is this a bug I file an issue for?

Don't overwrite the model. Instead, pass it to fromJSON so the model is updated:
ko.mapping.fromJSON(json, joe);
http://jsfiddle.net/Gc89Q/2/

Related

Angular - How to create 2d array in angular dynamically?

I Have been trying to figure out how can I make this array dynamically and send it to my api. The structure of array is given below.
Photos[image][0] = "a.png"
Photos[image][1] = "b.png"
Photos[image][2] = "c.png"
How can I do this in controller I am stuck every time I apply some solution I get this error Cannot set property '0' of undefined angular array. I think I still dont know what kind of array is this. so far I have implement this solution but God knows why is this headache.
I have three files in this object
$scope.files = [file,file,file].
and i need to put them in the array in the required format I mentioned above. This is my code.
for (var i = 0; i < $scope.file.length; i++) {
Photos[image] = {};
Photos[image][i]= $scope.file[i];
}
console.log(Photos);
Please elaborate my mistake.
I would check out the documentation for angular foreach.
Angular.forEach
This will allow you to iterate over each file in $scope.files. Each file can then be added to your Photos array as you see fit.

How can I copy the contents of a Javascript object to an empty one?

I have a Javascript object (JSON returned from a database) for use in an Angular site:
[{'widget_id':'1','widget_name':'Blue Widget','widget_description':'A nice blue widget','widget_discount':'20'},{'widget_id':'2','widget_name':'Red Widget','widget_description':'A fantastic red widget','widget_discount':'0'}]
I want to process this information before I use it in my view - say I want to alter the discount or perform some other operations. Therefore I want to make a new object, iterate through my JSON, and write certain values from the JSON object to the new, blank object.
For now I've just been trying to test copying one value from the old array to a new one, in my Angular controller:
WidgetSvc.fetchWidgets().success(function(response){
var rawWidgets = response
var widgetsOutput = {}
for (var i in rawWidgets){
widgetsOutput[i].widget_id = rawWidgets[i].widget_id
}
But this throws a cannot set property 'widget_id' of undefined error. I suspect I'm not initializing the new object properly.
What am I doing wrong?
You just forgot to set you nested object before setting property :
var rawWidgets = [{'widget_id':'1','widget_name':'Blue Widget','widget_description':'A nice blue widget','widget_discount':'20'},{'widget_id':'2','widget_name':'Red Widget','widget_description':'A fantastic red widget','widget_discount':'0'}];
var widgetsOutput = {}
for (var i in rawWidgets){
widgetsOutput[i] = {}
widgetsOutput[i].widget_id = rawWidgets[i].widget_id
}
console.log(widgetsOutput)
JSON != Javascript Object. You can JSON.parse() to make your JSON into a proper Javascript object:
WidgetSvc.fetchWidgets().success(function(response){
var data = JSON.parse(response);
// now you can do
data[0].widget_discount = 10;
}

Create an array of JavaScript objects from an existing array of objects

my first time posting a question here, so please let me know if I'm missing any information that is needed. Updated to include desired output.
I'm working on a google app script (basically javascript) and am trying to pull objects from an array of objects and create a new array of objects. I'm using the google base functions for getRowData (these can be found at : https://developers.google.com/apps-script/guides/sheets) to create my initial array of objects. This gives me a row of data similar (A JIRA export if anyone is wondering, with information cut):
{summary=Internal - Fix PuppetFile Jenkins Jobs, progress=1.0, issueType=Story, resolution=Done, timeSpent=3600.0, key=XXXXX-646, watchers=0.0, remainingEstimate=0.0, numberOfComments=1.0, status=Resolved, assignee=XXXXXXXX}
When I run my function:
for (var i = 0; i < issueList.length; i++){
rankList[i] = [issueList[i].summary,issueList[i].storyPoints,issueList[i].epicLink,issueList[i].fixVersions];
}
I get:
[Internal - Fix PuppetFile Jenkins Jobs, 3.0, null, null]
But what I want is:
{summary=Internal - Fix PuppetFile Jenkins Jobs, storyPoints=1.0, epicLink=StoryName, fixVersions=Done}
I'm not getting the key for the value, and I don't understand how the objects are constructed quite well enough to get it to transfer over. I looked at some examples of manipulating the key/value pairs but when I tried it on my own I just got a bunch of undefined. Thank you for any help you can provide.
What you want is probably something like this:
rankList = [];
for (var i = 0; i < issueList.length; i++) {
issue = issueList[i];
rankList.push({
summary: issue.summary,
storyPoints: issue.progress,
epicLink: issue.IDONTKNOW,
fixVersions: issue.resolution
});
}
I don't know what field goes in epicLink, since it wasn't obvious from your example. And I was just guessing about the other fields. But this is the general structure, you just need to make all the correct correspondences.
Use jquery each instead it's much easier to get the keys and value at the same time:
var myarray = [];
$.each(issueList,function(key,value){
console.log(key);
console.log(value);
value.key = key;
myarray.push(value);
});
console.log(myarray);

KnockoutJS, mapping plugin, get notified when changes in model?

Im using knockoutJS in following way:
var messagesFromServer = getJSONData().messages; //this get msgs from server
ko.mapping.fromJS(messagesFromServer, {}, myobject.viewModel.Messages);
Then i am basically calling this every three seconds to update html table, and it works just fine, new rows are added if new data found from server. Now i would like to add custom callback when something has actually changed, for example when new messages are found.
How should i implement this?
thanks in adv,
-hk
You could convert the two objects into json, then compare them json strings.
var messagesFromServer = getJSONData().messages; //this get msgs from server
var newString = ko.toJSON(messagesFromServer);
var oldString = ko.toJSON(myobject.viewModel.Messages);
if(newString != oldString ) {
// something new
}
ko.mapping.fromJS(messagesFromServer, {}, myobject.viewModel.Messages);
See ko.toJSON doc
I hope it helps.
If the messages is array, you can use ko.utils.compareArrays to detect the changes and raise custom events yourself. Here is code example for comparing ko.observableArray(). Look for Comparing two arrays

Javascript pushing objects into array changes entire array

I'm using a specific game making framework but I think the question applies to javascript
I was trying to make a narration script so the player can see "The orc hits you." at the bottom of his screen. I wanted to show the last 4 messages at one time and possibly allow the player to look back to see 30-50 messages in a log if they want. To do this I set up and object and an array to push the objects into.
So I set up some variables like this initially...
servermessage: {"color1":"yellow", "color2":"white", "message1":"", "message2":""},
servermessagelist: new Array(),
and when I use this command (below) multiple times with different data called by an event by manipulating servermessage.color1 ... .message1 etc...
servermessagelist.push(servermessage)
it overwrites the entire array with copies of that data... any idea why or what I can do about it.
So if I push color1 "RED" and message1 "Rover".. the data is correct then if I push
color1"yellow" and message1 "Bus" the data is two copies of .color1:"yellow" .message1:"Bus"
When you push servermessage into servermessagelist you're really (more or less) pushing a reference to that object. So any changes made to servermessage are reflected everywhere you have a reference to it. It sounds like what you want to do is push a clone of the object into the list.
Declare a function as follows:
function cloneMessage(servermessage) {
var clone ={};
for( var key in servermessage ){
if(servermessage.hasOwnProperty(key)) //ensure not adding inherited props
clone[key]=servermessage[key];
}
return clone;
}
Then everytime you want to push a message into the list do:
servermessagelist.push( cloneMessage(servermessage) );
When you add the object to the array, it's only a reference to the object that is added. The object is not copied by adding it to the array. So, when you later change the object and add it to the array again, you just have an array with several references to the same object.
Create a new object for each addition to the array:
servermessage = {"color1":"yellow", "color2":"white", "message1":"", "message2":""};
servermessagelist.push(servermessage);
servermessage = {"color1":"green", "color2":"red", "message1":"", "message2":"nice work"};
servermessagelist.push(servermessage);
There are two ways to use deep copy the object before pushing it into the array.
1. create new object by object method and then push it.
servermessagelist = [];
servermessagelist.push(Object.assign({}, servermessage));
Create an new reference of object by JSON stringigy method and push it with parse method.
servermessagelist = [];
servermessagelist.push(JSON.parse(JSON.stringify(servermessage));
This method is useful for nested objects.
servermessagelist: new Array() empties the array every time it's executed. Only execute that code once when you originally initialize the array.
I also had same issue. I had bit complex object that I was pushing in to the array. What I did; I Convert JSON object as String using JSON.stringify() and push in to the Array.
When it is returning from the array I just convert that String to JSON object using JSON.parse().
This is working fine for me though it is bit far more round solution.
Post here If you guys having alternative options
I do not know why a JSON way of doing this has not been suggested yet.
You can first stringify the object and then parse it again to get a copy of the object.
let uniqueArr = [];
let referencesArr = [];
let obj = {a: 1, b:2};
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
obj.a = 3;
obj.c = 5;
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
//You can see the differences in the console logs
console.log(uniqueArr);
console.log(referencesArr);
This solution also work on the object containing nested keys.
Before pushing, stringify the obj by
JSON.stringify(obj)
And when you are using, parse by
JSON.parse(obj);
As mentioned multiple times above, the easiest way of doing this would be making it a string and converting it back to JSON Object.
this.<JSONObjectArray>.push(JSON.parse(JSON.stringify(<JSONObject>)));
Works like a charm.

Categories

Resources