Knockout, get JSON from View Model after mapping it - javascript

I start with empty view model, then I do an ajax request for data from database. Collected data I mapping using Knockout.Mapping plugin to view model.
Like this:
var myName = new function(){
this.viewModel = {};
var getData = function () {
var mapping = {
'Members': {
create: function (options) {
return new UserMode(options.data);
}
}
}
$.ajax({
url: 'api/board',
data: $.param({"BoardId": 1}),
dataType: 'json',
success: function (data, textStatus, jqXHR) {
this.viewModel = ko.mapping.fromJS(data, mapping);
ko.applyBindings(this.viewModel);
},
});
}
};
Then I opened a JavaScript console in Chrome and typed:
ko.toJSON(myName.viewModel);
And results is
"{}"
I expected to see viewModel with data from server, not empty object.

You made a little confusion, I think you should call applybindings before doing your AJAX loading stuff.
I updated one of my old fiddle to replicate your problem, check it out, hope it will help you!
http://jsfiddle.net/ingro/Buscp/

Related

Knockout observablearray of observables with arrayMap function

I have a problem creating observable array of observables. I search on google but didn't find a solution. It may be something simple that I can't notice, because I'm new to Knockout.
But I have the model:
eventsModel = function () {
var self = this;
self.endTimeInMinutes = ko.observable();
self.events = ko.observableArray([]);
self.startTripTime = ko.observable();
self.endTripTime = ko.observable();
}
and I want to have an observables items in my array so I write a ViewModel and bind the model.
eventItemViewModel = function(o) {
var self = this;
self.BeginInMinutes = ko.observable(o.BeginInMinutes);
self.Type = ko.observable(o.Type);
};
var events = new eventsModel();
ko.applyBindings(events);
And I'm fetching the data using AJAX:
function GetEvents() {
$.ajax({
url: "Contact.aspx/GetEvents",
async: true,
type: "POST",
contentType: "application/json",
dataType: "json",
success: function (data) {
var temp = data.d;
endTimeInMinutes = temp["EndInMinutes"];
eventsArr = temp["Events"];
eventsArray = JSON.parse(JSON.stringify(eventsArr));
events.events(eventsArray);
},
});
}
After this I have an observable array but without observables values inside. Now I trying to add in my AJAX method:
events.events(ko.utils.arrayMap(eventsArray, function(eve) {return new eventItemViewModel(eve); }));
But if I do console.log on this, then I am getting array of objects, and in each object there is a BeginInMinutes and Type, but it's value is like function d()... etc.
I'm really get stucked with it, and I believe I made some very simple mistake somewhere.
Thanks for helping me.
You already got an observableArray with observable element inside it,Your problem really is with getting those values
use this code to get the real value of the first element in the array.
console.log(events.events()[0].BeginInMinutes());

Knockout JS binnding the ajax result

I am new to Knockout JS, I am trying to bind the ajax result data to Knockout JS viewmodel, but I am facing the problem while binding the data to view, I have create model and viewmodel and I am getting the result from ajax. Need help.
Below is my code:
// ajax on page load///
$.ajax({
type: "POST",
dataType: "json",
url: baseUrl + 'api/xxx/xxx',
data: UserProfileModel,
success: function(data) {
result = data;
////view model////
userDetailsViewModel(result);
},
error: function(error) {
jsonValue = jQuery.parseJSON(error.responseText);
//jError('An error has occurred while saving the new part source: ' + jsonValue, { TimeShown: 3000 });
}
});
//// view model///
var userDetailsViewModel = function(result) {
console.log(result);
self = this;
self.user = ko.observable(new userModel(result));
};
$(document).ready(function() {
ko.applyBindings(userDetailsViewModel());
});
/// Model////
function userModel(result) {
this.name = ko.observable();
this.userName = ko.observable();
}
Your userDetailsViewModel is a function that returns undefined. You'll either have to use new or create a return statement if you want it to create an actual viewmodel. E.g.:
var UserDetailsViewModel = function(result) {
var self = this;
self.user = ko.observable(new UserModel(result));
};
var mainUserDetailsViewModel = new UserDetailsViewModel(data);
You'll have to store a reference if you want to update your viewmodel from the scope of the ajax callback. Alternatively, you could make the ajax functionality part of the viewmodel. The easiest example:
var mainUserDetailsViewModel = new UserDetailsViewModel(data);
$.ajax({
success: function(data) {
mainUserDetailsViewModel.user(new UserModel(data));
}
});
Make sure you use this model in your applyBindings call:
ko.applyBindings(mainUserDetailsViewModel);
Note that I've used CapitalizedNames for functions that need to be instantiated, and uncapitalizedNames for instances of those functions. Following default naming conventions might help keeping track of what's what.

javascript, array of string as JSON

I'm having problems with passing two arrays of strings as arguments in JSON format to invoke ASMX Web Service method via jQuery's "POST".
My Web Method is:
[ScriptMethod(ResponseFormat=ResponseFormat.Json)]
public List<string> CreateCollection(string[] names, string[] lastnames)
{
this.collection = new List<string>();
for (int i = 0; i < names.Length; i++)
{
this.collection.Add(names[i] + " " + lastnames[i]);
}
return this.collection;
}
Now, the js:
function CreateArray() {
var dataS = GetJSONData(); //data in JSON format (I believe)
$.ajax({
type: "POST",
url: "http://localhost:45250/ServiceJava.asmx/CreateCollection",
data: dataS,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
//something
}
})
}
GetJSONData() is my helper method creating two arrays from column in a table. Here's the code:
function GetJSONData() {
//take names
var firstnames = $('#data_table td:nth-child(1)').map(function () {
return $(this).text();
}).get(); //["One","Two","Three"]
//take surnames
var surnames = $('#data_table td:nth-child(2)').map(function () {
return $(this).text();
}).get(); //["Surname1","Surname2","Surname3"]
//create JSON data
var dataToSend = {
names: JSON.stringify(firstnames),
lastnames: JSON.stringify(surnames)
};
return dataToSend;
}
Now, when I try to execude the code by clicking button that invokes CreateArray() I get the error:
ExceptionType: "System.ArgumentException" Message: "Incorrect first
JSON element: names."
I don't know, why is it incorrect? I've ready many posts about it and I don't know why it doesn't work, what's wrong with that dataS?
EDIT:
Here's dataToSend from debugger for
var dataToSend = {
names: firstnames,
lastnames: surnames,
};
as it's been suggested for me to do.
EDIT2:
There's something with those "" and '' as #Vijay Dev mentioned, because when I've tried to pass data as data: "{names:['Jan','Arek'],lastnames:['Karol','Basia']}", it worked.
So, stringify() is not the best choice here, is there any other method that could help me to do it fast?
Try sending like this:
function CreateArray() {
var dataS = GetJSONData(); //data in JSON format (I believe)
$.ajax({
type: "POST",
url: "http://localhost:45250/ServiceJava.asmx/CreateCollection",
data: {names: dataS.firstnames,lastnames: dataS.surnames} ,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
//something
}
})
}
This should work..
I think since you are already JSON.stringifying values for dataToSend property, jQuery might be trying to sending it as serialize data. Trying removing JSON.stringify from here:
//create JSON data
var dataToSend = {
names : firstnames,
lastnames : surnames
};
jQuery will stringify the data when this is set dataType: "json".
Good luck, have fun!
Altough, none of the answer was correct, it led me to find the correct way to do this. To make it work, I've made the following change:
//create JSON data
var dataToSend = JSON.stringify({ "names": firstnames, "lastnames": surnames });
So this is the idea proposed by #Oluwafemi, yet he suggested making Users class. Unfortunately, after that, the app wouldn't work in a way it was presented. So I guess if I wanted to pass a custom object I would need to pass it in a different way.
EDIT:
I haven't tried it yet, but I think that if I wanted to pass a custom object like this suggested by #Oluwafemi, I would need to write in a script:
var user1 = {
name: "One",
lastname:"OneOne"
}
and later pass the data as:
data = JSON.stringify({ user: user1 });
and for an array of custom object, by analogy:
data = JSON.stringify({ user: [user1, user2] });
I'll check that one later when I will have an opportunity to.

Store and access data on server using PHP and AJAX

I have a website that has the possibility to add comments which are just stored temporarily, when you reload the page the comments are gone. I save the comment data in an ObservAbleArrayList using knockout and javascript. One idea I had was to send this ObservAbleArrayList to my server, store it and then when the page is reloaded the stored arraylist would first update the commentfield. How could I do this with AJAX and PHP?
Here is my javascriptcode for the comments:
function Comment() {
var self = this;
self.nickname = ko.observable();
self.newMsg = ko.observable("");
self.editable = ko.observable(false);
self.addComment = function () {
vm.comments.push(self);
vm.selectedComment(new Comment());
};
self.deleteComment = function () {
vm.comments.remove(self);
};
self.editComment = function () {
self.editable(!self.editable());
};
}
function ViewModel() {
var self = this;
self.comments = ko.observableArray();
self.selectedComment = ko.observable(new Comment());
}
var vm = new ViewModel();
ko.applyBindings(vm);
});
Any help or examples would be very helpful! Thanks in advance.
Send the data as JSON to the server using jQuery as your bridge to handle the server side interaction with it's $.ajax() wrapper.
First, you need to mutate the data into a JSON object to be sent over and easily parsed. In knockout, you can use the .toJSON(model) method on a ko object to get the JSON interpretation of it, such as:
var jsonData = ko.toJSON(ViewModel);
Which will give you your JSON String. This is ready to be passed to the server, so now you can construct your $.ajax() call to your PHP script.
$.ajax({
url: '/path/to/my/script.ext',
type: 'GET', //default anyway, provided for clarity
dataType: 'json', //the returned data from the server will be automatically parsed as json
data: jsonData, //the KO model we converted earlier
success: function(data){
//the server's response is in "data" above, jsonParsed already.
}
});

wait for ajax result to bind knockout model

I have getGeneral function that calls ajax GET. When ajax recieves data (json), it creates KO model from given json and returns created KO.
When Knockout model is created and values are assigned, knockout applybindings should be called. Here is my code:
Defines GeneralModel and some related functions (inside "GeneralModel.js"):
var GeneralModel = function() {
//for now it is empty as data ar binded automatically from json
// CountryName is one of the properties that is returned with json
}
function getGeneral(pid) {
$.ajax({
url: "/api/general",
contentType: "text/json",
dataType: "json",
type: "GET",
data: { id: pid},
success: function (item) {
var p = new GeneralModel();
p = ko.mapping.fromJS(item);
return p;
},
error: function (data) {
}
});
}
This is called from another file (GeneralTabl.html), it should call get function and applyBindings to update UI:
var PortfolioGeneral = getGeneral("#Model.Id");
ko.applyBindings(PortfolioGeneral, document.getElementById("pv-portfolio-general-tab"));
However, in this scenario I am getting error (CountryName is not defined). This is because applyBindings happens before ajax returns data, so I am doing applyBindings to empty model with undefined properties.
Mapping from Json to Model happens here and is assignes values:
p = ko.mapping.fromJS(item);
I can also fill in GeneralModel with all fields, but it is not necessary (I guess):
var GeneralModel = function() {
CountryName = ko.observable();
...
}
It will still give an error "CountryName is not defined".
What is the solution?
1) Can I somehow move getGeneral inside GeneralModel, so get data would be part of GeneralModel initialization?
or
2) Maybe I should somehow do "wait for ajax results" and only then applyBindings?
or
I believe there are other options, I am just not so familiar with KO and pure JS.
Note: I fully understand that this is because Ajax is Async call, so the question is how to restructure this code taking into account that I have two seperate files and I need to call getGeneral from outside and it should return some variable.
Try using the returned promise interface:
function getGeneral(pid) {
return $.ajax({
url: "/api/general",
contentType: "text/json",
dataType: "json",
type: "GET",
data: {
id: pid
}
});
}
getGeneral("#Model.Id").done(function (item) {
var p = new GeneralModel();
p = ko.mapping.fromJS(item);
ko.applyBindings(p, document.getElementById("pv-portfolio-general-tab"));
}).fail(function () {
//handle error here
});

Categories

Resources