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.
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 have a problem with the Kendo AutoComplete widget.
I am trying it to query the datasource after the user has entered the first two characters of their search.
On the server (web api) I restrict the search using those two chars and all is well, i.e. a subset is returned and correctly shown and further filtered if I carry on typing in the search.
However, I then retype a new search entry which is no longer firing back to the datasource so I am stuck with the data that was retrieved from the first query.
How do I go about this properly?
Thanks
Here is my test code:
public class AlbumsController : ApiController
{
HttpRequest _request = HttpContext.Current.Request;
// GET api/albums
public IEnumerable<Album> GetForAutoComplete()
{
string sw = _request["sw"] == null ? "" : _request["sw"].ToString();
var query = (from a in Albums.MyAlbums
where a.Title.ToLower().StartsWith(sw)
orderby a.Title
select a).ToArray();
return query;
}
and my javascript on the client is like this:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/Albums/GetForAutoComplete",
data: {
sw: function () {
return $("#albumSearch").data("kendoAutoComplete").value();
}
}
}
}
});
$("#albumSearch").kendoAutoComplete({
dataSource: dataSource,
dataTextField: "Title",
minLength: 2,
placeholder: "type in here.."
});
Set serverFiltering to true. The default is false, so it will only grab data once and assume that it now has all the data, and subsequent filtering is done on the client.
To have it re-send to the server every time, add this:
var dataSource = new kendo.data.DataSource({
serverFiltering: true, // <-- add this line.
transport: {
...
}
});
The code for selecting an European country while typing using kendo autocomplete from database as below:
$("#countries").kendoAutoComplete({
dataTextField: "yourfield",
filter: "startswith", // or you can use filter: "contains",
minLength: 3, //what ever you want. In my case its 0.
placeholder: "Select country...",
dataSource: {
type: "get",
serverFiltering: true, //or can also make it false
transport: {
read: {
url: "/yourController/yourAction",
datatype: "json"
}
}
}
});
It works fine for me.
I'm using KendoUI to create charts from a remote datasource which is JSON file.
When I assign the url parameter(inside datasource object) a remote path ,pointing to the JSON the chart doesn't appear .
Say Like,
var myVar="some remote url";
dataSource: {
transport: {
read: {
url: myVar,
dataType: "json"
}
}
}
On the other hand if I directly specify the url as:
url: "http://myserver-name/somefile.json"
I can see the chart being displayed.
I cannot figure out what I'm doing wrong.
It should work! Check the following running on jsfiddle.
var url = "http://demos.kendoui.com/service/Products";
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: url,
dataType: "jsonp"
}
},
pageSize: 4,
schema: {
model: {
id: "ProductID",
fields: {
ProductID: {
editable: false,
nullable: true
},
ProductName: "ProductName"
}
}
}
});
$("#kendogrid").kendoGrid({
dataSource: dataSource,
columns: [
{
field: "ProductID",
title: "ID"},
{
field: "ProductName",
title: "Name"}
]
});
And this is the HTML:
<div id="kendogrid"></div>
It defines an external URL and sets it to a variable ( url) and then uses the resulting DataSource.
Check for differences or post a code as complete as possible in jsfiddle or jsbin.
well , your solution worked for me but in different way.I was getting the url value from a .cs file and storing inside an javascript variable.
var URL="<%=myCSvariable%>";
But this alone doesnt works...:(
I had to modifiy the URL variable value as,
var completeURL="\"" + URL + "\"";
and then create dataSource object as,
var mydataSource = new kendo.data.DataSource({
transport: {
read: {
url: URL, // this is the tricky part. Using 'completeURL' here doesnt creates my chart , instead 'URL' works just fine.
dataType: "json"
}
}
});
I know its STRANGE but that's how it worked for me..
Anyways, Thanks a ton..:)
I'm just starting out with Kendo mobile (impressed so far - coming from JQM). I'm trying to pass a postcode to a url which returns some json (houses near that area) and then append it to a listview using Datasource. However, it fails an in console I just get:
Error [object Object]
Heres my code: ** Updated **
var app = new kendo.mobile.Application(document.body,
{
transition:'slide'
});
function onBodyLoad() {
//document.addEventListener("deviceready", onDeviceReady, false);
// Use the following for testing in the browser
getProperties(onResult);
}
function getProperties(callback) {
var template = kendo.template($("#propertiesListViewTemplate").html());
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: 'http://www.someurl.me/getproperties.php?postcode=hx59ay',
dataType: "jsonp"
}
},
schema: {
data: "listing" //??? Not sure what this should be???
},
error: function(e) {
console.log("Error " + e);
},
change: function() {
$("#propertyResultListView").html(kendo.render(template, this.view()));
console.log(this.view());
}
});
dataSource.read();
$("#propertyResultListView").kendoMobileListView({dataSource:dataSource,template: $("#propertiesListViewTemplate").html()});
}
function onResult(resultData) {
console.log("Results " + listing);
$("#propertyResultListView").kendoMobileListView({dataSource: kendo.data.DataSource.create({data:resultData}),
template: $("#propertiesListViewTemplate").html()});
}
I'm sure this is down to the schema part of the Datasource but I'm lost as to what it should be (the docs havent really helped).
The JSON thats returned is:
{"country":"England","result_count":510,"longitude":-1.826866,"area_name":"Caldercroft, Elland HX5","listing":[{"image_caption":"Main Image","status":"for_sale","num_floors":"0","listing_status":"sale","num_bedrooms":"2","agent_name":"Daniel & Hirst","latitude":53.688934,"agent_address":"110 Commercial Street","num_recepts":"0","property_type":"Detached","country":"England","longitude":-1.843375,"first_published_date":"2012-10-11 19:05:42","displayable_address":"Elland HX5","street_name":"EXLEY LANE","num_bathrooms":"0","thumbnail_url":"http://images.zoopla.co.uk/f7f6791d95dadef11b340be2949bd8957079168f_80_60.jpg","description":"Comments","post_town":"Elland","details_url":"http://www.zoopla.co.uk/for-sale/details/26491359","agent_logo":"http://static.zoopla.co.uk/zoopla_static_agent_logo_(120721).png","price_change":[{"date":"2012-10-11 16:45:02","price":"37500"}],"short_description":"We are pleased to offer ...","agent_phone":"01484 954009","outcode":"HX5","image_url":"http://images.zoopla.co.uk/f7f6791d95dadef11b340be2949bd8957079168f_354_255.jpg","last_published_date":"2012-11-21 17:31:46","county":"West Yorkshire","price":"37500","listing_id":"26491359"}
Could someone point me in the right direction? The whole datasource schema is confusing to me. If it helps to describe what I'm trying to do in JQM I'd do something like
$.getJSON(serviceURL + 'getproperties.php?postcode=' + postcode + '&minimum_beds=' + minimumBeds + '&minimum_price=' + minimumPrice + '&maximum_price=' + maximumPrice , function(data) {
$('#propertyList li').remove();
// Loop through json data and append to table
listings = data.listing;
$.each(listings, function(index, property) {
console.log(property.image_url);
console.log(property.price);
$('#propertyList').append('<li><a href="propertydetails.html?id=' + property.listing_id + '">' +
'<img src="' + property.thumbnail_url + '"/>' +
'<h6>' + property.property_type + '</h6>' +
'<p>' + property.displayable_address + '</p>' +
'<p><strong>£' + property.price + '</strong></p>');
$('#propertyList').listview('refresh');
});
});
Template
<!-- Template for Property results, need to change below fields -->
<script type="text/x-kendo-template" id="propertiesListViewTemplate">
<h4>${property_type}</h4>
<p>${street_name}</p>
</script>
* Update - Code updated for Pechka answer **
I have now changed my service to return jsonp (with a callback) as per the link you mentioned. I can now see the jsonp in developer tool network tab -
jQuery17106739131917711347_1354193012656({"country":"England","result_count":179,"longitude":-1.83261282209016,"area_name":"Elland","listing":[{"image_caption":"","rental_prices":{"per_week":75,"accurate":"per_month","per_month":"325"},"status":"to_rent","num_floors":"0","listing_status":"rent","num_bedrooms":"1","agent_name":"Boococks","latitude":53.68668 ...
Nothing is getting populated into my template though, so no list view is created (I realize this is probably down to my newness to kendo). Can you see where I'm going wrong, this seems incredably tricky compared to JQM... Thanks again for your help.
Ok I'm just trying to simplify this thing to see where the error happens.
So you define your DataSource with a parameterMap and a Model:
var dataModel = new kendo.data.Model.define({
id: 'listing_id' //specifies a unique key, every other key is mapped automatically
});
var dataSource = new kendo.data.DataSource({
transport: {
parameterMap:function (_data, _operation) {
if (_operation == 'read') {
return {
postcode: 'bd11db' //sending parameters via parameterMap
};
}
},
read: {
url: 'http://www.someurl.me/getproperties.php',
dataType: "jsonp"
}
},
schema: {
//data: "ResultSet.Result" //data specifies which "node" to use for the actually returned data, since you want the complete object you dont need to specify this
model: dataModel //using the specified model
},
error: function(e) {
console.log("Error " + e);
},
change: function() {
$("#propertyResultListView").html(kendo.render(template, this.view()));
console.log(this.view());
}
});
dataSource.read();
Sorry I dont really see through all these callbacks at first glance, but this datasource should at least return (or log) the JSON you get from the serverMight not solve your problem completely, but may be a hint in the right direction ;) Feel free to comment on things that are unclear or (hopefully not) wrong Good Luck :)
I suggest you to configure your service to return jsonp (jsonwithpadding).
You can see the dataSource bound to a jsonp in action in this demo. Use the network tab of the browsers developer tools and see the difference in the format.
Try this:
Wrap your jsonp reply in a var like "results" so that it looks like this:
jQuery1820051476528169587255_1366217103715({"results":[{"id":"3","entry_stamp":"November 30, -0001 12:00 am","comments":null}]})
Designate the wrapper var:
schema: {
data: "results" //the portion of your jsonp that you want
}
Call the template:
$("#propertyResultListView").kendoMobileListView({
dataSource:dataSource,
template: $("#propertiesListViewTemplate").html()});
You shouldnt need to call dataSource.read(); as the call to the template will do this autoMagically. Try this below as a completed code view (i removed some other items that may cause issues - you will need to replace them once you get this simple version working:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: 'http://www.someurl.me/getproperties.php?postcode=hx59ay',
dataType: "jsonp"
}
},
schema: {
data: "results" //your reply data
}
});
$("#propertyResultListView").kendoMobileListView({
dataSource:dataSource,
template: $("#propertiesListViewTemplate").html()
});