I am passing in a JSON array to my JTable and am trying to use AJAX to show the data with no page load. This is an asp.net core mvc app with a C# back-end. The data loads, but as i said i do not have the ability to sort and all results are shown instead of only 10 per page as I request in the sorting param.
What do I ned to change here?
[Route("api/ca")]
public JsonResult Index()
{
var ListData = _context.CIModel.FromSql("StoredProcedureName").ToList();
return Json(new { Result = "OK", Records = ListData, TotalRecordCount = ListData.Count });
}
$('#btnTest').click(function () {
$('#jTableTest').jtable({
paging: true,
pageSize: '10',
sorting: true,
defaultSorting: 'Name ASC',
actions: {
listAction: function (postData, jtParams) {
return $.Deferred(function ($dfd) {
$.ajax({
url: 'https://localhost:44328/api/ca?jtStartIndex=' + jtParams.jtStartIndex + '&jtPageSize=' + jtParams.jtPageSize + '&jtSorting=' + jtParams.jtSorting,
type: 'GET',
dataType: 'json',
success: function (data) {
$dfd.resolve({ Records: data.records, Result: data.result, TotalRecordCount: data.TotalRecordCount });
},
error: function () {
$dfd.reject();
}
});
});
}
},
fields: {
name: {
title: 'Name',
width: '35%'
},
phone: {
title: 'Phone',
width: '15%'
},
yrsexp: {
title: 'Experience',
width: '15%'
}
}
});
$('#jTableTest').jtable('load');
});
Sorting and paging are both SERVER side operations. You need slight changes on both client and server.
On the client, in this example you don't need to write your own deferred function, Just give jTable the URL. It will then pass, paging (jtStartIndex and jtPageSize) and sorting (jtSorting) parameters to the server. These parameters are in the jtParams argument passed to the deferred function, so you have to forward them in you ajax call.
One the server, you need to respond to these sorting and paging parameters. Do note, that on a paged reply, TotalRecordCount is the total number of unpaged records. not the number returned. It is used by jTable to show the total number of pages.
Related
I am dealing with DataTables.AspNet nuget package to implement server-side pagination, searching and filtering.
I am trying to post my table name from ajax datatables to WebApi controller in order to get the specific C# DataTable to be returned as data source. I pack table name as a key-value pair of IDictionary<string, object> AdditionalParameters ("table" is a key). When the request is processed by Data method of WebApi controller, the IDataTablesRequest argument is always coming as null so I can't get my table name! Moreover, when I assign the table name explicitly and get DataTable, DataTablesResponse.Create() returns null.
So how can I force IDataTablesRequest to get data passed from datatables.js?
Client Side
function loadTable(type, editable) {
var url = "/api/Request/" + type;
$.ajax({
url: "/api/Request/Columns/" + type,
type: "GET",
statusCode: {
200: function (response) {
dtcolumns = response;
var columns = [];
if (editable) { columns.push({ data: null, className: 'select-checkbox', defaultContent: '' }); }
for (var i in dtcolumns) {
columns.push(
{
name: dtcolumns[i].Name,
title: dtcolumns[i].Caption,
data: dtcolumns[i].Name,
visible: !(dtcolumns[i].Caption === ""),
sortable: true,
searchable: true
});
}
var request_data = new Object();
var AdditionalParameters = {};
AdditionalParameters["table"] = type; // Table Name!
request_data.AdditionalParameters = AdditionalParameters;
var table = $('#just-table').DataTable({
deferRender: true,
bPaginate: true,
autoFill: {
horizontal: false
},
serverSide: true,
processing: true,
columns: columns,
ajax: {
url: "/api/Request/Data",
type: "POST",
//contentType: "application/json",
//dataType: "json",
//data: JSON.stringify(request_data),
data: request_data, //PASSING TABLE NAME TO WEBAPI CONTROLLER
statusCode: {
500: function (response) {
alert(response.responseJSON.Message)
}
}
},
rowId: 'ID',
scroller: {
loadingIndicator: true
},
targets: 0,
dom: 'BS<"toolbar">frtips'
});
}
}
})
}
Server Side
[HttpPost]
[Route("api/Request/Data")]
public JsonResult<IDataTablesResponse> Data(IDataTablesRequest request /*ALWAYS NULL!!!*/)
{
DataTable data = DBContext.GetInstance()[request.AdditionalParameters["table"].ToString()];
var filteredData = data.AsEnumerable().Where(row => row.ItemArray.Contains(request.Search.Value));
var dataPage = filteredData.Skip(request.Start).Take(request.Length).CopyToDataTable();
//ALWAYS NULL!!!
var response = DataTables.AspNet.WebApi2.DataTablesResponse.Create(request, data.AsDataView().Count, filteredData.Count(), dataPage);
return new DataTablesJsonResult(response, Request);
}
Your ajax query is GET yet the method is decorated with a POST attribute
Late to the reply, but here's my two cents worth as I had the same question.
An MVC controller cannot construct an interface as it doesn't know or understand which implementation of that interface to use.
Create a class that implements the interface and use that as the method parameter identifier.
see also: Passing an interface to an ASP.NET MVC Controller Action method
I am working on Kendo UI jQuery grid CRUD. I can get data display in the grid, but not adding new records.
When I click the update button to add a record after filling up columns in the pop-up window, nothing is posted to the server side as every property has a null value.
The picture shows what I got when the button is pressed.
Controller:
[HttpPost]
public JsonResult AddLostProperty(LostPropertyViewModel lostProperty)
{
try
{
using (var dbContext = new DBEntities())
{
if (lostProperty != null)
{
var newLostProperty = new sz_LostProperty()
{
Name = lostProperty.PropertyName,
CategoryId = dbContext.sz_PropertyCategory.Where(x => x.Name == lostProperty.CategoryName).Select(c => c.Id).FirstOrDefault(),
Description = lostProperty.PropertyDescription,
FoundDate = lostProperty.FoundDate,
FoundLocation = lostProperty.FoundLocation,
CratedDate = DateTime.UtcNow.Date,
CratedBy = ""
};
dbContext.sz_LostProperty.Add(newLostProperty);
dbContext.SaveChanges();
return Json(new { Success = true, Message = "The Property has been added." });
}
else
{
return Json(new { Success = false, Message = "No lost property added." });
}
}
}
catch (Exception e)
{
return Json(new { Success = false, Message = "Error: " + e });
}
}
JavaScript:
<script>
$(document).ready(function () {
var serviceBaseUrl = "#Request.Url.ToString()",
lostPropertyDataSource = new kendo.data.DataSource({
transport: {
create: {
url: serviceBaseUrl + "/AddLostProperty",
type: "POST",
dataType: "json",
complete: function (e) {
$('#manageLostPropertiesGrid').data('kendoGrid').dataSource.read();
}
},
read: {
url: serviceBaseUrl + "/GetLostProperties",
type: "GET",
dataType: "json"
},
update: {
url: serviceBaseUrl + "/UpdateLostProperty",
type: "PUT",
dataType: "json"
},
destroy: {
url: serviceBaseUrl + "/DeleteLostProperty",
type: "DELETE",
dataType: "json"
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) };
}
}
},
batch: true,
pageSize: 20,
schema: {
model: {
id: "PropertyId",
fields: {
PropertyId: { editable: false, nullable: true, type: "number" },
PropertyName: { type: "string", editable: true, validation: { required: true } },
CategoryId: { type: "number", editable: true, validation: { required: true } },
PropertyDescription: { validation: { required: false } },
Image: { validation: { required: false } },
FoundDate: { type: "Date" },
FoundLocation: { editable: true, validation: { required: false } }
}
}
}
});
$("#manageLostPropertiesGrid").kendoGrid({
dataSource: lostPropertyDataSource,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
{ field: "PropertyName", title: "Property Name", width: "150px" },
{ field: "CategoryName", title: "Category", editor: propertyCategoryList,/* template: "#=CategoryName#", */width: "150px"},
{ field: "PropertyDescription", title: "Description", width: "200px" },
{ field: "FoundDate", title: "Found Date", template: "#= kendo.toString(kendo.parseDate(FoundDate, 'dd-MM-yyyy'), 'dd-MM-yyyy') #", width: "130px" },
{ field: "FoundLocation", title: "Found Location", width: "120px" },
{ command: ["edit", "destroy"], title: " ", width: "250px" }],
editable: "popup"
}).data("kendoGrid");
});
From the browser, I can see the object sent to the server below:
What am I doing wrong?
I believe that in this case is problem in your parameter type at server side.
You have enabled batch: true editing which is useful if you want make many changes in your grid but send only one request with changed models in the end. It is very useful for example in case of inCell edit mode, when you would see many many requests and so decrease them is something you want, but in case of popup edit, I personally do not see any reason to use batch editing, but yes, I know Telerik has this in their demo.
So, because batch editing is enabled, there is called parameterMap before request is executed. (note: parameterMap is called only if you have batch edit enabled, otherwise it's ignored). That parameterMap wraps all your models into json string array and send that array with request to the server. In your case, there is always one record edited, but it doesn't matter - it will be sent as an array (in json string format).
Because it is sent as serialized string, you can
1) Change parameter of your AddLostProperty method to string models and then deserialize into array which allows you to work with it as you are used to
public ActionResult AddLostProperty(string models)
{
...
var data = JsonConvert.DeserializeObject<IEnumerable<LostPropertyViewModel>>(models);
...
}
2) If we will follow Telerik demo, you can use such implementation
public ActionResult AddLostProperty()
{
var products = this.DeserializeObject<IEnumerable<LostPropertyViewModel>>("models");
if (products != null)
{
//logic
}
return this.Jsonp(products);
}
3) And this is solution I would prefer
Just remove batch: true and parameterMap (since without batch it's useless) - and it should start send single object to your server method.
I'm working on an autocomplete that calls a method on my home controller, the javascript calls the method and returns the array. However the values do not display on the text box drop down, nothing does.
If I use a straight array as the source and don't call the home controller then it works just fine.
I don't see what I'm missing here, so I narrowed down the home controller method just to return an array using no logic until I figure this problem out.
Home Controller Method:
public string[] GetPatientName()
{
var names = new List<string> { "Bent","Boon","Book", "Al", "Cat", "Doe", "Ed", "Fox", "George" };
return names.ToArray();
}
Javascript:
<script language="javascript" type="text/javascript">
$(function() {
$('#tags').autocomplete({
source: function(request, response) {
$.ajax({
url: "/Home/GetPatientName",
data: "{ 'pre':'" + request.term + "'}",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success: function(data) {
response($.map(data.d,
function (item) {
alert(item);
return { value: item }
}));
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
},
delay: 0
});
});
</script>
HTML
<form>
<input id="tags" type="text" />
</form>
2 things:
1. From the top of my mind, if it wirked with a regular array and didnt work with the result of jQuery map function you probably need to ad .get() in order to get a clean array. To be precise
$.map(data.d,function (item) {
alert(item);
return { value: item }
}).get();
2. If that doesnt work, you would really have to share more data like what is the "response" function and exactly what response you are getting from the server (you could get that from the web browser's dev tools)
I am trying to use select2 with ASPX calling a webmethod. I am not able to get the ajax web method called within the select2 java script method above. any idea what i am doing incorrectly ?
this is my control on the page
<input type="hidden" id="attendee" style="width:300px;" /
this is my javascript code
$(document).ready(function () {
$('#attendee').select2(
{
placeholder: 'Enter name',
minimumInputLength: 1,
allowClear: true,
ajax:{
type: "POST",
url: "TestClientPage2.aspx/GetClientList",
dataType: 'json',
data: function (term, page) {
return {
pageSize: 20,
pageNum: page,
searchTerm: term
};
},
results: function (data, page) {
var more = (page * pageSize) < data.Total;
return { results: data.results, more: more };
}}});
});
This is my web method
public static string GetClientList(string searchTerm)
{
return #"{""employees"": [{ ""firstName"":""John"" , ""lastName"":""Doe"" }]}";
}
I am implementing jqGrid in my ASP.net web aplication, and I don't want to use the inbuilt filtering provided by jqGrid. So, I thought of using external filtering.
I will have a textbox. As soon as a user enters a value and clicks on the button filter, I would like to reload the grid. I am using server side pagination and I must do server side filtering.
I have some posts regarding this, but I was not able to find a solid example to demonstrate this.
I also dont know how the filter value is recieved in the C# code to do the filtering.
You can do it with postData parameter in jQGrid and pass your own values to filter and refresh grid
$(document).ready(SearchPatients);
and
function SearchPatients() {
'use strict';
jQuery("#patient-search-grid").jqGrid({
url: '/Patient/Search/',
datatype: 'json',
mtype: 'POST',
postData: { ID:function(){return $("#txtbkgID").val();} },
//postData:{search:function () { return getSearchPostData() } },
colNames: [{'Id','Pid','FullName'}],
colModel: [
{ name: 'Id', index: 'Id',hidden: true },
{ name: 'PatientIdentifier',index: 'PatientIdentifier'},
{ name: 'FullName', index: 'FullName'}
],
height: "100%",
pager: '#patient-search-pager',
rowNum: 10,
rowList: [10, 30, 50],
sortname: 'Id',
sortorder: 'desc',
viewrecords: true,
caption: "Search Results"
}
function getSearchPostData(){
var searchData = {};
searchData.PatientIdentifier = $('#patient-identifier').val();
searchData.FirstName = $('#first-name').val();
searchData.LastName = $('#last-name').val();
return JSON.stringify(searchData);
}
In Controller add optional parameter ID
[HttpPost]
public JsonResult Search(string ID)
{
//Request.Params["ID"] also will work
}