Update subsection of mapped knockout object - javascript

I know this question sounds familiar, but I have read so many of the similar questions and have not been able to find my specific situation.
I have a javascript object called gds (GlobalDataStructure). As its name suggests, this object contains all the information I need for all the web pages of my project and is stored in localStorage (hence why I am not just updating view model and need to map in the first place). It contains all sorts of feeds that are read via AJAX.
I use a constructor function to create gds. To massively simplify this structure and hopefully make this question simple, let's say gds was
function gdStructure(){
this.lastUpdate = new Date(2010,1,1);
this.family = new Object();
this.series = new Object();
this.product = new Object();
}
so I have
gds= new gdStructure();
then once i have populated the js array with data from initial feeds, I do the following.
viewmodel = ko.mapping.fromJS(gds);
ko.mapping.fromJS(gds,viewmodel);
The view model is then bound to each page with
ko.applyBindings(viewmodel);
So this all works no problem. This issue arises when I, for example, get a new family feed and I want to update that object. I can do the following
gds.family=feed;
ko.mapping.fromJS(gds,viewmodel);
And all would work fine, but that is mapping a MASSIVE JS object every time. This is extremely slow so I need to find a way where I can update just the feed that has changed. ideally something like..
ko.mapping.fromJS(gds.family, viewmodel.family);
But this appears not to work. Also because it is an OBJECT I can't just do.
viewmodel.family(gds.family)
Can anybody help me? I am sure this must be so simple.
Thanks in anticipation.

I think you have missunderstood how the lib works, this part looks very strange
viewmodel = ko.mapping.fromJS(gds);
ko.mapping.fromJS(gds,viewmodel);
Your using the definition as data?
Anyway, I use ko.mapping like this (A bit simplified but i think you get the point)
http://jsfiddle.net/QtyGd/1/

Related

angularJs form not adding object to array properly. 2 way binding not working

I have started a demo app and come across this problem where my parts that I am adding to the repairs are not being properly proccessed. This is my first angular that I am building.
To get the bug press update on one of the repair cards and then scroll down to the quantity and repair item section at the bottom of the form and try to add a new item. it doesnt regester what is in the form.
This is the codepen with the full view that doesnt work.
This is the function in the controller to pass the info the factory.
$scope.addPartsPerRepair = function() {
partFactory.addPartsPerRepair($scope.newPartsPerRepair);
$scope.newPartsPerRepair = {};
};
This is the function in the factory to add the new repair to the array partsPerRepair
factory.addPartsPerRepair = function(newPartsPerRepair) {
partsPerRepairs.push(newPartsPerRepair);
};
After I abstracted away the repair factory and simplified my view we are left with this
This is the codepen with the partial view that does work.
I have been over this code for the past 6 hours trying to fix this one probelm and I can not see my issue.
Secondly, This is more of an add-on question, Does anyone have any advice on how to save the partsPerRepair to the actual repair[Idx] instead of in one array called partsPerRepair that every repair accesses. I thought I might be able to add an array called parts to each repair and store quanity and item name in that array but that has proven to be more difficult then I can manage. I realize I am asking two different questions but since your here reading I figured you might be willing.
Thanks in advance for any help.
An updated CodePen.
So I've tried to resolve both your questions here, but all I have edited is the arra yof repairs and the add parts method, which means there is alot of cleaning up chanegs to be made like deleting the old partsPerRepairs and its references.
First thing newPartsPerRepair needed to be intialized this is why add parts was not working the function was passsing undefined(anything used as model in ng-model needs to be intialized), which is done in the controller - $scope.newPartsPerRepair = {};.
Second I moved the partsPerRepairs array into the repairs array and called it parts this is under each customer in the array, this is to answer your second question.
Third I changed the way the ng-repeats work to use these new parts arrays - ng-repeat="partsPerRepair in repairs[$index].parts track by $index"
Finally I moved and edited the addNewParts to the repairs factory so it used the new parts array and could access the repairs array.
Hope this all helps.

Angular 2 mysteriously modifies all sub-nested similar object within an object with the same value

As can be seen in the example at https://plnkr.co/edit/YyTPVQ?p=preview (Once loaded the app click on any of the names on the left bar)
If I modify any user's scale it also modifies the other user too.
Don't ask me why but, I somehow managed to fix it by deleting all .map and .js files, committed the fix to git, woke up this morning and now it doesn't work AGAIN (YES is a miraculous as it sounds!) https://github.com/thurft/appraisal
My problem is as follows the employees.component.ts handles the logic of employees.component.html
When I rate a question it modifies the same question of all this.employee instead of only doing it for this.selectedEmployee. This would be triggered updateQuestionRequest(question) and there is a console.log(this.employees) to show the Objects being modified.
In no way I modify this.employees array, so Angular somehow knows that it needs to modify the object in the array. But it also modifies all objects in that array that have the same question.
The question/problem is: How can I save the selectedEmployee rated question in the selectedEmployee OBJ instead of the value being saved across all employees OBJ?
I can't tell if is a bug on Angular or is a problem in my code, as sometimes it work, sometimes it doesn't and there is no consistency.
You have to clone TECHNICALQUESTIONS otherwise all employees will share the same reference:
employee[i].technicalQuestions = TECHNICALQUESTIONS.map(_=>{return Object.assign({}, _)};);
Because of Chrome not implmenenting yet the Object.assign the work around is to create a new json file to force the create of a new object employee[i].technicalQuestions = JSON.parse(JSON.stringify(TECHNICALQUESTIONS));

Variable Collection Name in Meteor? [duplicate]

Normally, MongoDB Collections are defined like this:
DuckbilledPlatypi = new Mongo.Collection("duckbilledplatypi");
I want to, though, dynamically generate Collections based on user input. For example, I might want it to be:
RupertPupkin20151212_20151218 = new Mongo.Collection("rupertPupkin20151212_20151218");
It would be easy enough to build up the Collection name:
var dynCollName = username + begindate +'_'+ enddate;
...and then pass "dynCollName") to Mongo.Collection:
= new Mongo.Collection(dynCollName);
...but what about the Collection instance name - how can that be dynamically generated? I would need something like:
"RupertPupkin20151212_20151218".ToRawName() = new Mongo.Collection(dynCollName);
-or:
"RupertPupkin20151212_20151218".Unstringify() = new Mongo.Collection(dynCollName);
...but AFAIK, there's no such thing...
On a single client instance, yes, and you could dynamically reference it. However in the general case (using it to sync data between the server and all connected clients), no.
I address this point in the Dynamically created collections section of common mistakes in a little detail, but the fundamental problem is that it would be highly complex to get all connected clients to agree on a dynamically generated set of collections.
It's much more likely that a finite set of collections where some have a flexible schema, is actually what you want. As Andrew Mao points out in the answer to this related question, partitioner is another tool available to help address some cases which give rise to this question.

Accessing Rails child objects within Javascript

I'm very new to rails, so please bear with me. I haven't quite grasped all the "magic" just yet.
Basically I need to access Location objects in Javascript, which all contain 0-N Coordinates. I'm pretty sure the model is set up right, with each Coordinate having a location_id.
I managed to get a parsed JSON of Location objects using the following method: I put
def index
#locations = Location.all.to_json
end
in the controller, and accessed this in the view with
var theLocations = <%= #locations.html_safe %>;
when I show this variable in the log, however, it doesn't show the Coordinates, which kind of makes sense. Thing is, I was planning to iterate over all the Locations and for each one create a javascript var with the relevant coordinates. These vars would then be passed to Google maps as objects.
Basically I was planning on doing something like (pseudocode):
for(Location l in Locations){
get all Coordinate objects within Location
for(Coordinate c: Coordinates);
var myObject = new google.maps.LatLng(c.X, c.Y),
add myObject to list for this location.
}
}
I'm just not sure how to approach this. How can I get a reference to the Coordinates within the Locations?
The quick and dirty answer is to pass a parameter in your to_json call:
#locations = Location.all.to_json(:include => :coordinate)
You may also want to consider creating a custom JSON structure by overriding as_json and rendering the objects as JSON after that.

KnockoutJS: Update/Insert data to a viewModel using mapping

I've been trying to figure this out for quite some time now. I couldn't find anything that addresses this problem, but please correct me if I'm wrong.
The problem:
I have data from a JSON API comming in, with an nested array/object structure. I use mapping to initially fill the model with my data. To update this, I want to extend the model if new data arrives, or update the existing data.
As far as I found out, the mapping option key, should do this trick for me, but I might have misunderstood the functionality of the mapping options.
I've boiled down the problem to be represented by this example:
var userMapping = {
key: function(item) {
return ko.utils.unwrapObservable(item.id);
}
};
// JSON call replaced with values
var viewModel = {
users: ko.mapping.fromJS([], userMapping)
};
// Should insert new - new ID?
ko.mapping.fromJS([{"id":1,"name":"Foo"}, {"id":2,"name":"Bar"}], userMapping, viewModel.users);
// Should only update ID#1 - same ID?
ko.mapping.fromJS([{"id":1,"name":"Bat"}], userMapping, viewModel.users);
// Should insert new - New ID?
ko.mapping.fromJS([{"id":3,"name":"New"}, {"id":4,"name":"New"}], userMapping, viewModel.users);
ko.applyBindings(viewModel);​
Fiddle: http://jsfiddle.net/mikaelbr/gDjA7/
As you can see, the first line inserts the data. All good. But when I try to update, it replaces the content. The same for the third mapping; it replaces the content, instead of extening it.
Am I using it wrong? Should I try to extend the content "manually" before using mapping?
Edit Solution:
I solved this case by having a second helper array storing all current models. On new data i extended this array, and updated the view model to contain the accumulated items.
On update (In my case a WebSocket message), I looped through the models, changed the contents of the item in question, and used method valueHasMutated() to give notice of changed value to the Knockout lib.
From looking at your example code the mapping plugin is behaving exactly as I would expect it to. When you call fromJS on a collection you are effectively telling the mapping plugin this is the new contents of that collection. For example:
On the second line, How could it know whether you were updating or whether you had simply removed id:2?
I can't find any mention of a suitable method that treats the data as simply an update, although you could add one. Mapped arrays come with some helpful methods such as mappedIndexOf to help you find particular items. If you receive an update data set simply loop through it, find the item and update it with a mapping.fromJS call to that particular item. This can easily be generalized into reusable method.
You can use ko.mapping.updateFromJS() to update existing values. However, it does not add new values so that would be a problem in your instance. Take a look at the link below for more details.
Using updateFromJS is replacing values when it should be adding them
Yes, you should first collect all data into a list or array and then apply the mapping to that list. Otherwise you are going to overwrite the values in your viewModel.

Categories