I am using knockoutjs on an asp.net mvc page. I am using ajax to persist a form back to the server by calling ko.toJSON(viewModel) and then posting the results back to the server using jQuery. All of the properties on the view model are successfully serialized except for the Javascript date which is persisted as an empty object.
Declaration:
var viewModel = {
startTime: ko.observable(),
type: ko.observable(),
durationInMinutes: ko.observable(),
notes: ko.observable()
};
Save Data:
var postData = ko.toJSON(viewModel);
$.ajax({
url: "/data",
type: "POST",
data: postData,
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
console.log('success!');
},
error: function () {
console.log('fail!');
}
});
The console.log value of viewModel.startTime() is:
Date {Tue May 10 2011 11:30:00 GMT-0500 (Central Daylight Time)}
After line 1 of Save Data, the value of postData is:
{
"startTime": {},
"type": "1",
"durationInMinutes": "45",
"notes": "asfasdfasdfasdfasdfasdfasdfas",
"displayableStartTime": "10-May 11:30"
}
If I expand line 1 of Save Data to
var jsonEvent = ko.toJS(viewModel);
jsonEvent.startTime = viewModel.startTime();
var postData = JSON.stringify(jsonEvent);
The value of postData is:
{
"startTime": "2011-05-10T16:30:00.000Z",
"type": "1",
"durationInMinutes": "45",
"notes": "asfasdfasdfasdfasdfasdfasdfas",
"displayableStartTime": "10-May 11:30"
}
Can anyone explain what might be going on and how I might be able to get knockoutjs to handle the date object?
Given the current issue with ko.toJS and dates, one option would be to create a dependentObservable containing the real value that you want the server to deal with.
Something like:
var viewModel = {
startTimeForInput: ko.observable(),
type: ko.observable(),
durationInMinutes: ko.observable(),
notes: ko.observable()
};
viewModel.startTime = ko.dependentObservable(function() {
return this.startTimeForInput().toJSON();
}, viewModel);
ko.applyBindings(viewModel);
Now, when you call ko.toJSON you will get the startTime with the correct value that the server could use.
For older browsers, something like json2.js would include the .toJSON for Date objects.
I had a problem with ko.toJSON() giving me a bad date format when the date was DateTime.MinValue.
Though probably not a fix for your problem, this fix worked for my ko.toJSON() date problem:
var postData = JSON.parse(JSON.stringify(ko.toJSON(viewModel)).replace(/\"1-01-01/g, "\"0001-01-01"));
ASP.Net WebMethod fails because ko.toJSON() produces different results for DateTime.MinValue
Related
I am binding to a JSON data source, then rebinding after the user initiates a search based on filters on the page. The JSON payload is encoded improperly and nothing I've tried thus far seems to explain why.
If I could just add the correct JSON to the HTTP post, everything would work normally, and does with the $.ajax method listed first.
Using $.ajax call (works)
$.ajax(
{
url: '/api/DataProcessing',
type: "Post",
contentType: "application/json; charset=utf-8",
data: '' + JSON.stringify(searchObject),
dataType: 'json',
success: function (result) {
$(".kendoDataProcessing").data("kendoGrid").dataSource = new kendo.data.DataSource({ data: result });
$(".kendoDataProcessing").data("kendoGrid").dataSource.read();
$(".kendoDataProcessing").data("kendoGrid").refresh();
},
error: function (xhr, ajaxOptions, thrownError) {
alert('Status: ' + xhr.status + ', Error Thrown: ' + thrownError);
}
});
However, when I update the kendogrid data source in what I expect to send an equivalent payload, it encodes the JSON in an unexpected way (see below the code block for before and after HTTP requests captured in Fiddler. (encodes improperly)
$(".kendoDataProcessing").kendoGrid({
dataSource: {
transport: {
read: {
url: '/api/DataProcessing',
type: 'Post',
contentType: 'application/json; charset=utf-8',
data: '' + JSON.stringify(searchObject),
dataType: 'json',
}
},
pageSize: 25
},
height: 620,
sortable: true,
pageable: true,
filterable: true,
columns: [
{
field: "Client",
title: "Client Name",
width: 120
}, {
field: "Study",
title: "Study",
width: 100
}, {
field: "DataLogId",
title: "Batch Description",
width: 120
}, {
field: "Indicator",
title: "Indicator",
width: 100
}, {
field: "UserName",
title: "Username",
width: 110
}, {
field: "AssessmentPoint",
title: "Assessment Point",
width: 130
}, {
field: "DateStamp",
title: "Date Stamp",
width: 180
}]
});
**Expected JSON encoding (HTTP call created using $.ajax method) **
{"Client":"Choose a client...","Study":"Choose a study...","UserName":"Choose a user...","from":"","To":"","AssessmentPoint":"Choose an AP...","Indicator":"Choose an indicator...","DataLogId":""}
**Actual JSON encoding (HTTP call created using Kendogrid data source update and rebind **
0=%7B&1=%22&2=C&3=l&4=i&5=e&6=n&7=t&8=%22&9=%3A&10=%22&11=C&12=h&13=o&14=o&15=s&16=e&17=+&18=a&19=+&20=c&21=l&22=i&23=e&24=n&25=t&26=.&27=.&28=.&29=%22&30=%2C&31=%22&32=S&33=t&34=u&35=d&36=y&37=%22&38=%3A&39=%22&40=C&41=h&42=o&43=o&44=s&45=e&46=+&47=a&48=+&49=s&50=t&51=u&52=d&53=y&54=.&55=.&56=.&57=%22&58=%2C&59=%22&60=U&61=s&62=e&63=r&64=N&65=a&66=m&67 ... (continues)
It looks like it is making the json string into an array of sorts. So I tried with just a test string of "floof" and it encoded to "0=f&1=l&2=o&3=o&4=f"
Controller method called:
public HttpResponseMessage Post([FromBody]DataProcessingSearch dataProcessingSearch)
{
// dataProcessingSearch var is null (was passed oddly encoded)
}
Additional Details (search object)
var searchObject = new Object();
searchObject.Client = $('#ClientList').val();
searchObject.Study = $('#StudyList').val();
searchObject.Site = $('#SiteList').val();
searchObject.UserName = $('#UserList').val();
searchObject.from = $('#beginSearch').val();
searchObject.To = $('#endSearch').val();
searchObject.AssessmentPoint = $('#AssessmentPointList').val();
searchObject.Indicator = $('#IndicatorList').val();
searchObject.DataLogId = $('#DataLogIdText').val();
demo: http://so.devilmaycode.it/json-encoded-improperly-when-using-kendogrid-post-payload
function searchObject(){
return {
Client : $('#ClientList').val(),
Study : $('#StudyList').val(),
Site : $('#SiteList').val(),
UserName : $('#UserList').val(),
from : $('#beginSearch').val(),
To : $('#endSearch').val(),
AssessmentPoint : $('#AssessmentPointList').val(),
Indicator : $('#IndicatorList').val(),
DataLogId : $('#DataLogIdText').val()
}
}
// i have putted the dataSource outside just for best show the piece of code...
var dataSource = new kendo.data.DataSource({
transport: {
read : {
// optional you can pass via url
// the custom parameters using var query = $.param(searchObject())
// converting object or array into query sring
// url: "/api/DataProcessing" + "?" + query,
url: "/api/DataProcessing",
dataType: "json",
// no need to use stringify here... kendo will take care of it.
// also there is a built-in function kendo.stringify() to use where needed.
data: searchObject
},
//optional if you want to modify something before send custom data...
/*parameterMap: function (data, action) {
if(action === "read") {
// do something with the data example add another parameter
// return $.extend({ foo : bar }, data);
return data;
}
}*/
}
});
$(".kendoDataProcessing").kendoGrid({
dataSource: dataSource,
...
});
comments are there just for better explanation you can completely remove it if don't need it. the code is fully working as is anyway.
doc: http://docs.telerik.com/kendo-ui/api/wrappers/php/Kendo/Data/DataSource
What May be the wrong perception:-
1.The Json() method accepts C# objects and serializes them into JSON
strings. In our case we want to return an array of JSON objects; to
do that all you do is pass a list of objects into Json().
public JsonResult GetBooks()
{
return Json(_dataContext.Books);
}
Can you identify what is wrong with the above method? If you didn't already know, the above method will fail at runtime with a "circular reference" exception.
Note: try to return Json, HttpResponse may serialize the data in such a way that it is not acceptable by Kendo Grid. this has happened with me in my project.
Try this Approach:-
Now lets create instances of them in a JsonResult action method.
public JsonResult GetFooBar()
{
var foo = new Foo();
foo.Message = "I am Foo";
foo.Bar = new Bar();
foo.Bar.Message = "I am Bar";
return Json(foo);
}
This action method would return the following JSON:
{
"Message" : "I am Foo",
"Bar" : {
"Message" : "I am Bar"
}
}
In this example we got exactly what we expected to get. While serializing foo it also went into the Bar property and serialized that object as well. However, let's mix it up a bit and add a new property to Bar.
I remember working with a kendo grid in the past. Solution back then was returning jsonp. (needed to work crossdomain not sure if it does in your case)
Suggestion change you controller method to return sjonp by decorating you method with a JsonpFilterAttribute. Something like so:
[JsonpFilter]
public JsonResult DoTheThing(string data, string moreData)
{
return new JsonResult
{
Data = FetchSomeData(data, moreData)
};
}
Then in de Kendo grid try use http://demos.telerik.com/kendo-ui/datasource/remote-data-binding.
For the Jsonpfilter attribute first look at here or else here.
I have three parameters startdate, enddate and name which I have to send to the server to get back Json response. I am displaying the response in a GridPanel.
My Ajax Request looks like this:
FilterOperSet: function(button){
var win = button.up('window');
var form = win.down('form');
var start = form.getForm().findField('startDate').getSubmitValue();
var end = form.getForm().findField('endDate').getSubmitValue();
var act = form.getForm().findField('actor').getSubmitValue();
Ext.Ajax.request({
url: 'ListData',
params: { type: 'recordedRequest', startDate: start,
endDate: end, actor: act, start:0,limit:10 },
success: function(response) {
var json = Ext.decode(response.responseText);
var mystore = Ext.data.StoreManager.lookup('RecordedRequestStore');
mystore.loadData(json.recordedRequests);
},
scope: this});
}
I have a button, when user enters values for startdate, enddate and name and clicks on the button the above listener sends them as parameters along with start and limit for paging and response is captured and stored in gridpanel.
My issue with paging toolbar is: I could see the following as response
recordedRequests
// has some meta data here
success
true
total
1339
But my paging tool bar show only one page and at bottom says 0 of 0 and to the right nothing to display. Infact it should say 1 of 14 and should allow me to go through next pages.
2) Also when I click on refresh button it calls my store and calls server, but i want to make a ajax request with startdate, enddate and name as parameters(which would be exactly what my button above listerner does)
My Store looks like this:
autoLoad: false,
remoteFilter: true,
buffered: false,
pageSize: 10,
//leadingBufferZone: 1000,
fields:['start', 'end', 'actor','serviceOp'],
proxy: {
type: 'ajax',
url: 'ListData',
store: 'RecordedRequestStore',
startParam:'start',
limitParam:'limit',
pageParam:'page',
reader: {
type: 'json',
root: 'recordedRequests',
successProperty: 'success',
totalProperty: 'total'
},
extraParams: {
'type': 'recordedRequest',
},
//sends single sort as multi parameter
simpleSortMode: true,
// Parameter name to send filtering information in
filterParam: 'query',
// The PHP script just use query=<whatever>
encodeFilters: function(filters) {
return filters[0].value;
}
},
listeners: {
filterchange: function(store, filters, options){
console.log( filters )
},
totalcountchange: function() {
console.log('update count: ')
//this.down('#status').update({count: store.getTotalCount()});
}
}
Any sort of help will of great value for me. Thanks in Advance.
Instead of Ajax Request. I should use
store.load(params{your params})
For nextpage and previouspage I used beforeload listener for custom parameters.
So I've been beating my head against the wall for a day or so trying to get this to work. if it's simple and stupid - sorry and thanks. It's pretty long post as I'm trying to describe everything I've done thus far.
So I have a ASMX web service that I would like to use to populate a Kendo UI listview. This works perfectly until I add the data: to my transport request. So my web service looks like this now:
WebMethod(Description = "Return All Pending Actions Based")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public PendingActionResult GetPendingActions(string sUsername, string sPassword, string sUserID, string sClubID)
{
//code is here;
}
And my full dataSource looks like this:
dataSource = new kendo.data.DataSource({
transport: {
read: {
type: "POST",
data: "{'sUsername':'admin#mail.com','sPassword':'13123','sUserID':'1539','sClubID':'1'}",
url: "http://sdk.domain.com/services/general.asmx/GetPendingActions",
contentType: "application/json; charset=utf-8",
dataType: "json"
}
},
schema: {
data: "d.Data", // ASMX services return JSON in the following format { "d": <result> }. Specify how to get the result.
total: "d.Total",
model: {
id: "activityID",
fields: {
activityID: { type: "number", validation: {min: 1, required: true } },
taskName: { type: "string" },
taskNote: { type: "string" },
openDate: { type: "datetime" },
dueDate: { type: "datetime" },
priority: { type: "number" },
statusID: { type: "number" },
openedByID: { type: "number" },
assignedToID: { type: "number" },
statusName: { type: "string" },
complete: { type: "bool" }
}
}
}
});
that.set("pendingActionsDataSource", dataSource);
The error I get back is:
{"Message":"InvalidJSONprimitive:"\u00261={\u00262=\u0027\u00263=s\u00264=U\u00265=s\u00266=e\u00267=r\u00268=n\u00269=a\u002610=m\u002611=e\u002612=\u0027\u002613=:\u002614=\u0027\u002615=a\u002616=d\u002617=m\u002618=i\u002619=n\u002620=#\u002621=m\u002622=a\u002623=i\u002624=l\u002625=.\u002626=c\u002627=o\u002628=m\u002629=\u0027\u002630=,\u002631=\u0027\u002632=s\u002633=P\u002634=a\u002635=s\u002636=s\u002637=w\u002638=o\u002639=r\u002640=d\u002641=\u0027\u002642=:\u002643=\u0027\u002644=1\u002645=3\u002646=1\u002647=2\u002648=3\u002649=\u0027\u002650=,\u002651=\u0027\u002652=s\u002653=U\u002654=s\u002655=e\u002656=r\u002657=I\u002658=D\u002659=\u0027\u002660=:\u002661=\u0027\u002662=1\u002663=5\u002664=3\u002665=9\u002666=\u0027\u002667=,\u002668=\u0027\u002669=s\u002670=C\u002671=l\u002672=u\u002673=b\u002674=I\u002675=D\u002676=\u0027\u002677=:\u002678=\u0027\u002679=1\u002680=\u0027\u002681=}\u002682=".","StackTrace":"atSystem.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(Stringinput,Int32depthLimit,JavaScriptSerializerserializer)\r\natSystem.Web.Script.Serialization.JavaScriptSerializer.DeserializeT\r\natSystem.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContextcontext,WebServiceMethodDatamethodData)","ExceptionType":"System.ArgumentException"}
So I started searching high and low for anything that was similar and found other people missing a ' or a " in the data request so I tried a ton of different variations of it, tried using JSON.stringify but the error continued. So I went to fiddler to see what was being sent to the server and here is my problem. Junk is being sent. Fiddler shows this in TextView being sent to the server:
0=%7B&1='&2=s&3=U&4=s&5=e&6=r&7=n&8=a&9=m&10=e&11='&12=%3A&13='&14=a&15=d&16=m&17=i&18=n&19=%40&20=m&21=a&22=i&23=l&24=.&25=c&26=o&27=m&28='&29=%2C&30='&31=s&32=P&33=a&34=s&35=s&36=w&37=o&38=r&39=d&40='&41=%3A&42='&43=1&44=3&45=1&46=2&47=3&48='&49=%2C&50='&51=s&52=U&53=s&54=e&55=r&56=I&57=D&58='&59=%3A&60='&61=1&62=5&63=3&64=9&65='&66=%2C&67='&68=s&69=C&70=l&71=u&72=b&73=I&74=D&75='&76=%3A&77='&78=1&79='&80=%7D
(I'll post a picture online of this so it's a little easier to see)
So here I can clearly see that the string isn't being sent in the correct format. So I decided to give this a go without using Kendo dataSource but instead just use JSON/AJAX. So I typed this up:
function getPAs() {
$.ajax({
type: "POST",
url: "http://sdk.domain.com/services/general.asmx/GetPendingActions",
data: "{'sUsername':'admin#mail.com','sPassword':'13123','sUserID':'1539','sClubID':'1'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: getPAs_Success,
error: app.onError
});
}
function getPAs_Success(data, status) {
console.log("START getPAs_Success");
var cars = data.d;
var sout = document.getElementById('nav');
var output = "";
$.each(cars, function(index, car) {
output += '<p><strong>' + car.taskName + ' ' +
car.taskNote + '</strong><br /> Priority: ' +
car.priority + '<br />Status: ' +
car.statusID + '<br />Opened By: ' +
car.openedByID + '<br />Assigned To' +
car.assignedToID + '</p>';
});
sout.innerHTML = output;
console.log("END getPAs_Success");
}
And if I look at fiddler in TextView I see this being sent to the server:
{'sUsername':'admin#mail.com','sPassword':'13123','sUserID':'1539','sClubID':'1'}
And I clearly see my JSON results in fiddler as well.
So my question is after all of that:
Is there something special I need to be doing with the Kendo UI Datasource in order to pull this off? If it matters, I'm using Icenium and trying to build a quick mobile app for fun.
Thanks,
Richard
UPDATE #1
Tried both and no further.
data: {"sUsername":"admin#mail.com","sPassword":"13123","sUserID":"1539","sClubID":"1"},
which validates using jsonlint.com but when I look at fiddler now I see this being sent to the server:
sUsername=admin%40mail.com&sPassword=13123&sUserID=1539&sClubID=1
So maybe it's because I don't have quotes around the data now so I tried this:
data: '{"sUsername":"admin#mail.com","sPassword":"13123","sUserID":"1539","sClubID":"1"}',
and when I do that I get same mess of 0=%7... like above.
When I try to use toJSON I get an object function has no method. Doing something like this:
var jsPost = $.toJSON({
sUsername: "admin#mail.com",
sPassword: "13123",
sUserID: "1539",
sClubID: "1"
});
Found someone on the telerik forums which said not to use toJSON and instead use JSON.stringify so I tried this:
var jsPost = {
sUsername: "admin#mail.com",
sPassword: "13123",
sUserID: "1539",
sClubID: "1"
};
...
data: JSON.stringify(jsPost),
But still results in the crazy garbage.
A valid JSON format needs double quotes, instead of single. You can try validating your string in services like http://jsonlint.com/ . Even better, you can use toJson on an object instead of building it manually.
I am making a very simple mistake but couldn't able to find it.
I posted JSON object to CodeIgniter controller using AJAX but was not able to retrieve this value in the controller function.
My code is
AJAX code:
$.ajax({
type: "POST",
contentType: "application/json",
data: "{eventdata:" + JSON.stringify(eventToSave) + "}",
url: "<?php echo $base?>/index.php/welcome/addEvent",
dataType: "json",
success: function (data) {
alert(data);
$('#calendar').fullCalendar('renderEvent', event, true);
$('.qtip').remove();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
debugger;
}
});
In the console, JSON object is shown in following format:
{
eventdata: {
"EventID": 170,
"StartDate": "Thu May 10 2012 00:00:00 GMT+0530 (India Standard Time)",
"EndDate": "Thu May 10 2012 00:00:00 GMT+0530 (India Standard Time)",
"EventName": "sdsfddsf"
}
}
CodeIgniter addEvent function:
$json_output[]=(array)json_decode($this->input->post());
print_r($json_output);
I have tried various other options also but couldn't able to get the value from json object which I need to store in database.Please tell me some way to retrieve this value from json object and then storing it in db
Try this one if it work.
$json = file_get_contents('php://input');
$json = stripslashes($json);
$json = json_decode($json);
convert the object array to array
$array = (array) $json;
This looks wrong.
url: "<?php echo $base?>/index.php/welcome/addEvent",
Are you sure you are actuelly hitting the right controller method? Did you check the source code?
Try doing something like this instead (using the URL Helper):
url: "<?php echo site_url('welcome/addEvent'); ?>",
I have a view(MVC3) that users place orders from. The view is bound to a model that i use to display modelitems from. There are two functionalities on this view. First you enter the customers details and then you choose the items the user has ordered. This is the code i´m using to build another model to be sent back to serverside:
var modelItems = {
ModelID: [],
Amount: []
};
var serviceModel = {
Name: $.trim($('#name').val()),
Customernumber: $.trim($('#customernumber').val()),
Address1: $.trim($('#address1').val()),
Address2: $.trim($('#address2').val()),
Zipcode: $.trim($('#zipcode').val()),
City: $.trim($('#city').val()),
Country: $.trim($('#country').val()),
Phone: $.trim($('#phone').val()),
Mobile: $.trim($('#mobile').val()),
Email: $.trim($('#email').val())
};
$('div.modelSpan').each(function (i) {
var textBox = $(this).children();
var value = $(textBox).val();
if (value != '0' && value != '') {
var modelID = $(textBox).attr('name');
modelItems.ModelID.push(modelID);
modelItems.Amount.push(value);
}
});
var accessory = {
ModelItems: modelItems,
ServiceModel: serviceModel
};
$.ajax({
url: '/Site/Order', //Renamed sec reasons
type: "POST",
data: JSON.stringify(accessory),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (ordernumber) {
window.location.href = "/Site/OrderInfo/" + businessAB + "/" + ordernumber;
},
error: function () {
alert('error');
}
});
Cool thing in MVC3 is that my accessory automatically binds to my model on serverside called AccessoriesModel. On callback success i´m setting new href to a receipt site to show user what has been created. This all works but my issue is that i would like the receipt view(OrderInfo) to be returned from my controller that receives the [httppost] and not setting new href. Is there a way to do this? This is easy when using regular form submit but because the values for my model dont come from one form it complicates things. Maybe I shouldn´t use AJAX?
You could use knockout JS with Ajax and render your pages with a mixture of JavaScript objects and regular html.