Knockout view model serialize to db and retrieve - javascript

I Have web form which use knockout and i have to implement a new feature to save form as a draft to db and later load again to modify or submit.
Is there any feature on knockout framework to serialize viewmodel to any other form(like json) that i could save to db. then later load it and populate my view easily.
I know that i can save viewmodel as a json to db and then later i can load it and fill each property on view model like below. but im looking for a feature like serialize and later populate whole viewmodel at once using it.I have lot of properties and i don't want to fill each property by writing a code line as below.
var someJSON = /* fetched the saved viewmodel as a json */;
var parsed = JSON.parse(someJSON);
// Update view model properties
viewModel.firstName(parsed.firstName);
viewModel.pets(parsed.pets);

Use the mapping plugin and replace your code with that one:
var someJSON = /* fetched the saved viewmodel as a json */;
var parsed = JSON.parse(someJSON);
// Update view model properties
viewModel = ko.mapping.fromJS(data);

You can use the mapping plugin as other questions have mentioned here, but it definitely isn't perfect.
Most notably, if you have object properties, they won't be converted into observables.
var pojo = {
someStringProperty: 'lol',
someObjectProperty: { }
};
var vm = ko.mapping.fromJS(pojo);
if(!ko.isObservable(vm.someObjectProperty)) console.log('FAIL!');
I've looked into forking, but it's kinda not worth it. I just post-process the object graph looking for properties that aren't observable and that contain an object and convert them into observable properties.

Related

Get entire model in Backbone JS

In backbone javascript models, we get individual items as shown below:
var type = this.model.get("type");
Here, type will be defined in server side & then fetched in JS using above syntax.
My question is how do I get the entire model in one shot?
I tried this.model.toString() but it prints [object object]
Any suggestion?
EDIT: I'm using above line of code in backbone view & not the model. And in this view, I need to read all the models data even if its JSON string, thts fine with me. How do I get it. I don't want to use separate collection or anything else. I need to update the above view only to get entire model.
You can use model.toJSON() to get all the attributes of a model.
you use a collection
http://backbonejs.org/#Collection
You can then iterate though the collection to obtain each model.
var Library = Backbone.Collection.extend({
model: Book
});
for example and then
books = new Library();
books.each(function(book) {
book.publish();
});
to iterate

Saving and restoring an observableArray containing nested observableArrays

I have a model which I need to save to JSON and re-load as required. The idea is that the user can save the model to a basket or database (as a JSON string) and then reload it. It's simple enough to create the JSON and save it but re-loading is seemingly much more difficult. The problem is that my model includes some complex objects similar to the Knockout Contacts example:
http://knockoutjs.com/examples/contactsEditor.html
I can even generate the JSON and pass it via a web service into an .NET object.
I've looked at the Knockout documentation for loading a data model:
http://knockoutjs.com/documentation/json-data.html
...and I can easily restore my "simple" observables but I don't see how I can initialise my arrays of complex objects where these objects also contain observable arrays. Any ideas?
I've even tried using the mapping plugin but the resulting JSON doesn't contain the information in the arrays.
Doing this creates the JSON and all my data is in there:
var jsonData = JSON.stringify(ko.toJS(self.contacts), null, 2)
Ideally, I just need to reverse this or at least create all the objects one by one.
Thanks for looking :)
The mapping plugin should work. I'm not sure if i understood correctly your situation, but try somethig like that:
ViewModel = function() {
this.contacts = ko.observableArray();
}
var model = new ViewModel();
ko.applyBindings(model);
var json = '{"contacts":[{"name":"Tom","phones":["00000000","1111111111"]},{"name":"Bill","phones":["222222222","333333333"]},{"name":"Bert","phones":["444444444","55555555"]}]}';
ko.mapping.fromJSON(json, {}, model);
The observableArray of "contacts" and "phones" in each contact are deserialized correctly from the json string.
http://jsfiddle.net/k4Sth/1/

How do I serialize data from non-form elements and make it accessable from params[:model]

I have a Sinatra app which loads information from an external API and displays it on a page. This is done in Sinatra which gets the information and puts it a temporary model instance (which is NOT saved), so it is easier to access all its propertys in the view.
Now when the user clicks a link I want the model instance to be saved to the database, which I think only can be done via AJAX etc. because the last request already finished and none of the instances is still alive. I thought I needed to extract all the information of the corresponding HTML elements and make an AJAX-Post to another route.
My problem is now, I want to be able to create(and save) the model using #model = Model.create(params[:model]). It would be clear what to do using a form, but that is not an option because all the data is displayed within a table and each table row is one instance of the model.
How do I serialize the data from the table row in which the clicked link is, so I can use it as described above?
UPDATE
I am using MULTIPLE instances of the object class, each in one tablerow!
I am using DataMapper, only the temporary objects are not stored!
I dont want to clutter up my whole setup!
Did you consider ActiveResource? You can use ActiveResource to maintain object state. If your REST API follows convention it would be very easy to map resource.
Regarding second half sending back data to your controller, you could store in hidden variable(s) and on post it should be easy to construct back the object and persist it to database.
Something like
#model
class MyModel < ActiveResource::Base
# set configs here
end
# To fetch record from REST API in controller or whatever
MyModel.find(1)
#in controller on form submit or AJAX
post "/path" do
MyModel.new(params[:myModel])
end
Update
To maintain state of object without using hidden form
in javascript you can have something like
var myModel = #{myModel.to_json}; #Ruby interpolation in HAML it will depend on templating language
on certain action you can update the JSON object
and to post using AJAX
$.post("post/path", myModel);
More Update
In External JS
function my_js_function(obj) {
/* do something useful here like setting up object hash etc
*/
}
In Ruby Template
<script>
var myObj = #{myObj.json}
my_js_function(myObj);
</script>
I found a pretty easy solution. It was nothing more than getting all the required values from the DOM and putting them into an Array!
application.js:
$(".enable").click(function() {
var table_row = $(this).closest("tr");
var model_array = new Array;
var elements_with_information = jRow.find("[name]");
elements_with_information.each(function() {
// Doing some checking on which kind of element
// it actually is and then basically doing:
model_array.push($(this).text());
});
// Constructing nested array to use `params[:model]`
var data = { "model" : {
"property1": model_array[0],
"property2": model_array[1]
}};
// Now doing the AJAX request
$.ajax({
url: "/model/doshit",
type: "POST",
data: data
});
});

How to initialize a Knockout viewmodel when initial viewmodel load is empty

I am using Knockout to implement a course list selection tool. I am using the approach below to populate the data (MVC3/Razor), so that when the viewmodel is initially populated, I have no issues working with each KO array (i.e. CourseList, ScheduleList). However, when the initial load from the server returns zero rows, meaning that the viewmodel 'ScheduleList' property is empty, then it's not possible to call any methods such as .push() or .removeAll(). Presumably this means that the observable array was never created since there was nothing to fill it with. When the model is filled, the ScheduleList property is populated with a List. What is the best way to instantiate it when the MVC action returns it as empty? There is a jsFiddle that seems to address it, but when I try to use the 'create' option, it renders my entire model blank. I am not sure what the syntax is of the 'create' option. The jsFiddle is here: http://jsfiddle.net/rniemeyer/WQGVC/
// Get the data from the server
var DataFromServer = #Html.Raw(Json.Encode(Model));
// Data property in viewmodel
var data = {
"CourseList": DataFromServer.CourseList ,
"ScheduleList": DataFromServer.ScheduleList
};
$(function() {
// Populate Data property
viewModel.Data = ko.mapping.fromJS(data);
// ko.applyBindings(viewModel, mappingOptions);
ko.applyBindings(viewModel);
});
When the initial page load does not populate ScheduleList, then the following code throws an error. If the initial page load contained data, then you could call .removeAll() and .push() etc.
var oneA= 'abc';
// push not working
this.Data.ScheduleList.push( oneA );
Set up your mapping parameters to make it so on creation, you give it a certain structure. Then it will do the updates for you.
What is most likely happening is that your DataFromServer doesn't actually contain a ScheduleList property at all. So when it is mapped, a corresponding property is never made. The mapper will only map existing properties to observables.
You need to set in your create options for the view model to add empty arrays when either array is not set. That way, your view model will end up with corresponding observable arrays in place.
By ensuring that CourseList or ScheduleList is an array, the mapped view model will map them as observableArray objects so your code will work as you expected.
var DataFromServer = {
'CourseList': [1,2,3]
//, 'ScheduleList': []
};
var dataMappingOptions = {
'create': function (options) {
var data = options.data;
data.CourseList = data.CourseList || [];
data.ScheduleList = data.ScheduleList || [];
return ko.mapping.fromJS(data);
}
};
viewModel.Data = ko.mapping.fromJS(DataFromServer, dataMappingOptions);
var data = {
CourseList: DataFromServer.CourseList || ko.observableArray([]) ,
ScheduleList: DataFromServer.ScheduleList || ko.observableArray([])
};

Backbone.js: Decoding the Fetched Data

Using Backbone.js I need to perform the following tasks:
1) fetch the data from the server
2) Decoding the Fetched Data (perform some operation on this data)
3) Inject these data to my view and then my HTML template
About the task number two (Decoding the Fetched Data ),
what is the best place/way/pattern to make it in a MVC context?
Some of the data to encode are about the rights and look like this:
READ = 0x01,
CREATE_USER = 0x08,
CREATE_WORKSPACE = 0x10,
UPDATE = 0x20,
I need to encode them making Bit Operations with a mask.
You could provide your own parse implementation in the model:
parse model.parse(response)
parse is called whenever a model's data is returned by the server, in fetch, and save. The function is passed the raw response object, and should return the attributes hash to be set on the model.
So you'd have something like this:
parse: function(response) {
var parsed_response = _(response).clone();
// do your bit wrangling on parsed_response and remove what you don't want...
return parsed_response;
}
The best place to do this within a MV* framework like Backbone.js would likely be a model. The Backbone model can be more of a presentation model in the Model View Presenter sense which contains shared presentation logic in the form of computed properties. If the derived property is only ever used in a single view, then an argument can be made for just sticking it into the view.
One thing you may want to do is to bind the underlying property to the computed property so that any changes are automatically reflected.

Categories