How to get part of JSON for KendoDataSource - javascript

I need to fill a KendoListView from a external server and I need to use just part of the response I am reading for a Java Servlet
var srcListView = new kendo.data.DataSource({
transport: {
read: {
dataType: "json",
url: "MainServlet",
data:{event:"Test"},
},
},
});
And the response is:
{
"status": "ok",
"response": {
"trucks": [
"A6U-905",
"AHF-888",
"AHP-779",
"buzz"
]
}
}
I need just the trucks array for kendoListView, I am using Kendo-ui, How I can do this?

As an alternative to what #DontVoteMeDown said about using schema.parse you can use a simpler solution for cases like this where you don't need to process the result but just return what is in an element. This solution is define schema.data as the name of the field containing the data. In your example:
new kendo.data.DataSource({
transport: {
read: {
dataType: "json",
url: "MainServlet",
data:{event:"Test"},
}
},
schema: {
data: "response.trucks"
}
});
I recommend using schema.parse when you need to do some transformation on the data received and schema.data when is simply returning some sub-element of the received JSON.

Use dataSource.schema.parse to filter the data to be used in the widget:
new kendo.data.DataSource({
transport: {
read: {
dataType: "json",
url: "MainServlet",
data:{event:"Test"},
}
},
schema: {
parse: function(data) {
return (data && data.trucks ? data.trucks : []);
}
}
});

Related

Ajax wont call MVC controller method

I have an AJAX function in my javascript to call my controller method. When I run the AJAX function (on a button click) it doesn't hit my break points in my method. It all runs both the success: and error:. What do I need to change to make it actually send the value from $CSV.text to my controller method?
JAVASCRIPT:
// Convert JSON to CSV & Display CSV
$CSV.text(ConvertToCSV(JSON.stringify(data)));
$.ajax({
url: '#Url.Action("EditFence", "Configuration")',
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: { value : $CSV.text() },
success: function(response){
alert(response.responseText);
},
error: function(response){
alert(response.responseText);
}
});
CONTROLLER:
[HttpPost]
public ActionResult EditFence(string value)
{
try
{
WriteNewFenceFile(value);
Response.StatusCode = (int)HttpStatusCode.OK;
var obj = new
{
success = true,
responseText = "Zones have been saved."
};
return Json(obj, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
var obj = new
{
success = false,
responseText = "Zone save encountered a problem."
};
return Json(obj, JsonRequestBehavior.AllowGet);
}
}
RESULT
You should change the data you POST to your controller and the Action you POST to:
data: { value = $CSV.text() }
url: '#Url.Action("EditFence", "Configuration")'
The $CSV is possible a jquery Object related to an html element. You need to read it's text property and pass this as data, instead of the jQuery object.
Doing the above changes you would achieve to make the correct POST. However, there is another issue, regarding your Controller. You Controller does not respond to the AJAX call after doing his work but issues a redirection.
Update
it would be helpful for you to tell me how the ActionResult should
look, in terms of a return that doesn't leave the current view but
rather just passes back that it was successful.
The Action to which you POST should be refactored like below. As you see we use a try/catch, in order to capture any exception. If not any exception is thrown, we assume that everything went ok. Otherwise, something wrong happened. In the happy case we return a response with a successful message, while in the bad case we return a response with a failure message.
[HttpPost]
public ActionResult EditFence(string value)
{
try
{
WriteNewFenceFile(value);
Response.StatusCode = (int)HttpStatusCode.OK;
var obj = new
{
success = true,
responseText= "Zones have been saved."
};
return Json(obj, JsonRequestBehavior.AllowGet));
}
catch(Exception ex)
{
// log the Exception...
var obj = new
{
success = false,
responseText= "Zone save encountered a problem."
};
return Json(obj, JsonRequestBehavior.AllowGet));
}
}
Doing this refactor, you can utilize it in the client as below:
$CSV.text(ConvertToCSV(JSON.stringify(data)));
$.ajax({
url: '#Url.Action("EditFence", "Configuration")',
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: { value = JSON.stringify($CSV.text()) },
success: function(response){
alert(response.responseText);
},
error: function(response){
alert(response.responseText);
}
});
If your javascript is actually in a JS file and not a CSHTML file, then this will be emitted as a string literal:
#Url.Action("EditFile", "Configuration")
Html Helpers don't work in JS files... so you'll need to point to an actual url, like '/configuration/editfile'
Also, it looks like you're posting to a method called EditFile, but the name of your method in the controller code snippet is EditFence, so that will obviously be an issue too.
you dont need to add contentType the default application/x-www-form-urlencoded will work because it looks like you have a large csv string. So your code should be like this example
$(document).ready(function() {
// Create Object
var items = [
{ name: "Item 1", color: "Green", size: "X-Large" },
{ name: "Item 2", color: "Green", size: "X-Large" },
{ name: "Item 3", color: "Green", size: "X-Large" }
];
// Convert Object to JSON
var $CSV = $('#csv');
$CSV.text(ConvertToCSV(JSON.stringify(items)));
$.ajax({
url: '#Url.Action("EditFence", "Configuration")',
type: "POST",
dataType: "json",
data: {value:$CSV.text()},
success: function(response) {
alert(response.responseText);
},
error: function(response) {
alert(response.responseText);
}
});
Your problem is on these lines:
success: alert("Zones have been saved."),
error: alert("Zone save encountered a problem.")
This effectively running both functions immediately and sets the return values of these functions to the success and error properties. Try using an anonymous callback function.
success: function() {
alert("Zones have been saved.");
},
error: function() {
alert("Zone save encountered a problem.")
}

Properly Initialize Client Side Model

My issue is very simple. I am using ASP Web API, Entity Framework, Angular, and Kendo UI. I have 2 classes, FREQUENCY and FREQ_TYPE_. Class FREQUENCY has a navigation property to class FREQ_TYPE. I have a kendo ui grid that loads 10 class FREQUENCY models. Each class FREQUENCY model has it's FREQ_TYPE data loaded properly. My problem is that when I create a new row in my kendo ui grid and try to save the row to the server, I get an error saying the navigation property FREQ_TYPE needs to be initialized. This is expected of course since kendo doesn't know how to auto=initialize my nav properties.
What is the best practice for giving my angular JS client the knowledge it needs to create a new class FREQ_TYPE so I can properly initialize class FREQUENCY and save it to the server? My models only exist as code-first entity models, so I can't just create a new model in my client side JS as it doesn't know about these models. Is there some framework that can generate local model classes from an EF database? Or do I just have to manually set all the json fields for my class FREQ_TYPE navigation property? Or is there an easier way for me to use Web API so that I can make a request to "figure out" what the model info is and create a client side JS model without needing to have a "local model"?
Here is the client side grid and datasource:
$(document).ready(function () {
var crudServiceBaseUrl = "http://localhost:29858/";
var NIICDDS = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "api/NIICDFreq",
dataType: "json"
},
update: {
url: function (data) {
console.log("DATA TEST");
console.log(data);
return crudServiceBaseUrl + "api/NIICDFreq/";
},
// url: crudServiceBaseUrl + "api/VHFMasterLists",
dataType: "json",
data: function (data) {
console.log("returning data in update TEST");
console.log(data.models[0]);
return data.models[0];
},
type: "PUT",
contentType: "application/json; charset=utf-8",
},
destroy: {
url: crudServiceBaseUrl + "api/NIICDFreq",
dataType: "json"
},
create: {
url: crudServiceBaseUrl + "api/NIICDFreq",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8"
},
parameterMap: function (model, operation) {
if (operation !== "read" && model) {
return kendo.stringify(model);
} else {
return kendo.stringify(model) ;
}
}
},
batch: true,
pageSize: 20,
schema: {
data: function (data) { //specify the array that contains the data
console.log("DATA RETURN TEST");
console.log(data);
return data || [];
},
model: {
id: "Id",
fields: {
Id: { editable: false,
nullable: false,
type: "number"
},
Frequency: { type: "string" }
}
}
}
});
$("#NIICDFreqGrid").kendoGrid({
dataSource: NIICDDS,
columns: [
{ field: "Id", title: "Freq ID", format: "{0:c}", width: "120px" },
{ field: "Frequency", title: "Frequency Test", format: "{0:c}", width: "120px" },
{ command: ["edit", "destroy"], title: " ", width: "250px" }
],
toolbar: ["create"],
editable: "inline"
});
});
And here is the web api controller:
[ResponseType(typeof(FREQUENCY))]
public IHttpActionResult PostFREQUENCY(FREQUENCY testfreq)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.FREQUENCIES.Add(testfreq);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (FREQUENCYExists(testfreq.Id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = testfreq.Id }, testfreq);
}
The error is the last line:
iisexpress.exe Information: 0 : Request, Method=POST, Url=http://localhost:29858/api/NIICDFreq, Message='http://localhost:29858/api/NIICDFreq'
iisexpress.exe Information: 0 : Message='NIICDFreq', Operation=DefaultHttpControllerSelector.SelectController
iisexpress.exe Information: 0 : Message='CFETSWebAPI.Controllers.Frequency.NIICDFreqController', Operation=DefaultHttpControllerActivator.Create
iisexpress.exe Information: 0 : Message='CFETSWebAPI.Controllers.Frequency.NIICDFreqController', Operation=HttpControllerDescriptor.CreateController
iisexpress.exe Information: 0 : Message='Selected action 'PostFREQUENCY(FREQUENCY testfreq)'', Operation=ApiControllerActionSelector.SelectAction
iisexpress.exe Information: 0 : Message='Value read='DomainModelModule.FREQUENCY'', Operation=JsonMediaTypeFormatter.ReadFromStreamAsync
iisexpress.exe Information: 0 : Message='Parameter 'testfreq' bound to the value 'DomainModelModule.FREQUENCY'', Operation=FormatterParameterBinding.ExecuteBindingAsync
iisexpress.exe Information: 0 : Message='Model state is invalid.
testfreq.FREQ_POOL: The FREQ_POOL field is required.,testfreq.FREQ_TYPE: The FREQ_TYPE field is required.', Operation=HttpActionBinding.ExecuteBindingAsync
And of course testfreq has all null values.
Thank you for your help.
Since you shared no code, I can only make an assumption. However, I think you're confused with the error message. Neither Kendo or Angular are responsible. They do not "initialize" classes. You said yourself, the data is there on the client.
From what it sounds like to me, the data arrives at your controller action, and the compiler does not know how to initialize your class. Make sure your Class B has a constructor defined in your server-side code. Even an empty constructor will suffice, unless the members of the class need explicit initialization themselves.
public class B {
// constructor
public B() {
// initialize class members
}
}

Kendo TreeView making request on expand but not showing returned data

I have a Kendo TreeView control that will load the first level of nodes, but when I attempt to expand one the expand triangle disappears. I can see that the ajax call is being made and returning valid Json as noted below, any ideas?
Here's the TreeView setup,
this.dataSource = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "...",
dataType: 'json'
}
},
});
this.treeview = $(this.settings.selector).kendoTreeView({
dataSource: this.dataSource,
}).data("kendoTreeView");
And the Initial returned Json,
[{"id":"00000000-0000-0000-0000-000000000000","text":"Root Node","hasChildren":true,"spriteCssClass":"folder"}]
And finally the Json returned on node expansion,
[{"id":"8295b0c3-8f85-4c2d-8fc6-fe43be8a734b","text":"Folder A","hasChildren":false,"spriteCssClass":"folder"}]
Ok, so it started to work after renaming the properties on my model to not be the same as the defaults for the datasource. I had to rename id, hasChildren, and text.
My TreeView setup ended up as,
this.dataSource = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "...",
dataType: 'json'
}
},
schema: {
model: {
id: "itemId",
hasChildren: "isExpandable"
}
}
});
this.treeview = $(this.settings.selector).kendoTreeView({
dataSource: this.dataSource,
dataTextField: 'name'
}).data("kendoTreeView");

Kendo Grid CRUD: how make update

i have a kendo ui grid with asp web api as backend. When i call the create method in the kendo ui, it's called the following method in web api
public IHttpActionResult PostProduct(ProductDTO product)
{
...
...
return StatusCode(HttpStatusCode.NoContent);
}
Now if i try to edit the item in the Kendo Ui Grid is called again the create method instead of the update method.
If i reload the page (so is called the read method of kendo ui grid), the update method works.
What's the problem? I have the following schema:
schema: {
model: {
id: "Id",
fields: {
Id: { editable: false, type: "number" },
Name: { validation: { required: true } },
Description: { editable: true },
Price: { editable: true },
Active: { type: "boolean" },
}
}
}
I have the following transport (omitted some code)
$scope.tabellaProdotto = new kendo.data.DataSource({
transport: {
read: {
url: function () {
return "api/Prodotti/GetProdottoPerTipoProdotto/" + productTypeMainSelected;
},
dataType: "json"
},
create: {
url: "api/Prodotti/PostProdotto",
dataType: "json",
data: function (prodottoTmp) {
...
},
type: "POST"
},
update: {
url: function (prodotto) {
return "api/Prodotti/PutProdotto" + prodotto.Id
},
data: function (prodottoTmp) {
...
},
type: "PUT",
dataType: "json"
UPDATE: the problem seems be the return of the web api action method:
return CreatedAtRoute("DefaultApi", new { id = p.Id }, p);
Now works but the p object size dimension is very high: i must return the entire object?
This sounds like the Grid is not getting the Json back in the right format.
Be sure to use the KendoMVC DataSourceRequest Object to return data in the right format.
Here is an example:
public ActionResult Update([DataSourceRequest] DataSourceRequest request, MyViewModel data)
{
var result = UpdateBackend(data);
return Json(result.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}

Kendo DataSource appends Schema Id on datasoure sync

Just want to know why push method of the javascript inserts "index"
var agendaBatch=[];
for(var i=0; i<agendas.length; i++) {
var agenda = {
MeetingId: meetingId,
Title: agendas[i].title,
Description: agendas[i].description,
Remarks: "",
};
agendaBatch.push(agenda);
}
console.log(kendo.stringify(agendaBatch));
dataSourceAgenda.add(agendaBatch);
dataSourceAgenda.sync();
output:
{"0":{"Title":"Agenda title","Description":"Agenda details","Remarks":""},
"1":{"Title":"Agenda title","Description":"Agenda details","Remarks":""}}
what I expect is this output to match my Web API parameter requirement
[{"Title":"Agenda title","Description":"Agenda details","Remarks":""},
{"Title":"Agenda title","Description":"Agenda details","Remarks":""}]
Any suggestions how can I do this?....
UPDATE: just found out a moment ago, I'm using kendo ui datasource, I fixed the problem when I removed the Id on the schema
var dataSourceAgenda = new kendo.data.DataSource({
transport: {
type: "odata",
create: {
type: "POST",
url: API_URL + "/agendas",
contentType: "application/json; charset=utf-8",
dataType: 'json'
},
parameterMap: function (options, operation) {
if (operation !== "read" && options) {
return kendo.stringify(options);
}
}
},
schema: {
model: {
id: "Id", //I get my desired output if this is removed
fields: {
MeetingId: { type: "number" },
Title: { type: "string" },
Description: { type: "string" },
Remarks: { type: "string" },
}
},
}
});
HOWEVER I need to the Id parameter in other functions, is there anyway I can do this without removing the Id in kendo datasource.
Changed the Question title!
According the documentation of Kendo UI DataSource (here), add method accepts an Object not an array of Object.
In addition, you use as id a field called Id that is not among the fields of your model.
Try doing the following:
var dataSourceAgenda = new kendo.data.DataSource({
transport: {
create : function (op) {
...
},
parameterMap: function (options, operation) {
if (operation !== "read" && options) {
return kendo.stringify(options.models);
}
}
},
batch : true,
schema : {
model: {
id : "Id", //I get my desired output if this is removed
fields: {
Id : { type: "number" },
MeetingId : { type: "number" },
Title : { type: "string" },
Description: { type: "string" },
Remarks : { type: "string" }
}
}
}
});
I.e.:
Set batch to true for being able to send multiple requests at a time when you invoke sync.
Define Id in the schema.model.fields definition.
Do the stringify of options.models.
As agendaBatch is obviously an array, I assume that kendo.stringify is not serializing it properly. You could go with JSON.stringify.
Note that this is not implemented by older browsers. If you need to support them, you could include the script by Douglas Crockford:
https://github.com/douglascrockford/JSON-js/blob/master/json2.js
EDIT
Now that you changed your question - I am not really familiar with kendo ui, so this really is just a wild guess in an attempt to help you with your updated problem.
It looks like you have access to the data in the beforeSend function. You could try to manipulate it for your needs, like this maybe:
beforeSend: function (xhr, s) {
var arrayData = [];
for (var id in s.data) {
arrayData.push(s.data[id]);
}
s.data = arrayData;
}

Categories

Resources