Seems to be the usual problem with Kendo grids, but a dropdown being rendered into the toolbar needs to fire an Ajax request to the server and refresh the grid from the returned data. I can see in Fiddler that the Ajax call is successfully being actioned and data is definitely being returned but we're not getting anything refreshed on the grid.
Here's the View code:
<div class="grid-validation-error" id="unitgrid-validation-error">
</div>
#(Html.Kendo()
.Grid(Model)
.Name("WheelchairAlertsGrid")
.Sortable()
.Scrollable(scr => scr.Height("100%"))
.Filterable()
.ToolBar(t => t.Template(
#<text>
<div class="toolbar">
<label class="category-label" for="category">Show alerts for:</label>
#(Html.Kendo().DropDownList()
.Name("filter-periods")
.DataTextField("Text")
.DataValueField("Value")
.OptionLabel("Month")
.Events(e => e.Change("filterPeriodChange"))
.BindTo(new List<SelectListItem>(){
new SelectListItem{ Text = "Day", Value = "Day" },
new SelectListItem{ Text = "Week", Value = "Week" },
new SelectListItem{ Text = "Month", Value = "Month" } })
)
</div>
</text>
))
.Pageable(paging => paging.Messages(msg => msg.Display(ResourceManager.RetrieveResource("PagingFormat"))))
.Columns(
col =>
{
col.Bound(um => um.SerialNumber).Width(150).Title("Wheelchair").ClientTemplate
(
"<a href='" +
Url.DealerGroupAction("Index", "Wheelchair") +
"/#= WheelchairDataAssignmentId #'>#= SerialNumber #" + "</a>"
);
col.Bound(um => um.Name).Width(150);
col.Bound(um => um.ChargeAlert).Width(60);
col.Bound(um => um.BatteryAbuse).Width(60);
col.Bound(um => um.Flash).Width(60);
col.Bound(um => um.Transmission).Width(60);
col.Bound(um => um.DealerGroup).Width(100);
})
)
And here's the JS code to refresh the data (with assorted variations commented out that have also been tried but failed to yield results):
function filterPeriodChange(e) {
var ddl = $('#filter-periods').data('kendoDropDownList');
var grid = $('#WheelchairAlertsGrid').data("kendoGrid");
$.getJSON('#Url.DealerGroupWheelChairAlertsApiUrl("WheelchairAlerts")', { filterPeriod: ddl.value() }, function (data) {
grid.dataSource = data;
});
}
There's always something really simple causing these sorts of problems but I can't see the forest for the trees. Any assistance appreciated.
Cracked it.
The Kendo Grid data source needs to be told to expect Ajax content. So the code should look like the following:
... other stuff as above
.DataSource(ds => ds
.Ajax()
.PageSize(20)
)
The next piece of the puzzle is to ensure the data source is being set correctly after picking up the data:
function filterPeriodChange(e) {
var ddl = $('#filter-periods').data('kendoDropDownList');
var grid = $('#WheelchairAlertsGrid').data("kendoGrid");
$.getJSON('#Url.DealerGroupWheelChairAlertsApiUrl("WheelchairAlerts")', { filterPeriod: ddl.value() }, function (data) {
var dataSource = new kendo.data.DataSource({
data: data.Data,
pageSize: 20
});
grid.setDataSource(dataSource);
});
}
That seems to have sorted the issue. Now, changing my dropdown list at the top level calls my filterPeriodChange method, fires off an Ajax request and re-binds the data.
Related
This is my main grid. In action i go to the database and get all data. I want to put an another grid that will use same data type. And this grid will use same data source with filter that i specified. I don't want to go database again.
For example
Grid1: show all data
Grid2: show OrderAmount>100
(Html.Kendo().Grid<CustomerOrder>()
.Name("Orders")
.Events(events => events.DataBound("onDataBound"))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Read(read => read.Action("OrderListAjax", controller))
.PageSize(Constants.PageSize)
.Columns(columns =>
{
columns.Bound(p => p.CustomerNumber).Title("CustomerNumber");
columns.Bound(p => p.CustomerName).Title("CustomerName");
columns.Bound(p => p.OrderAmount).Title("OrderAmount");
})
)
I tried a different way in below and it works also.
// Take the data source from main grid
var mainSource = $("#Orders").data("kendoGrid").dataSource.data().toJSON();
// Prepare your query on main grid source
var orderAmountQuery = kendo.data.Query.process(mainSource, {
filter: {
logic: "and",
filters: [
{
field: "OrderAmount",
value: parseInt("100"),
operator: "gt" // greater than
}
]
}
});
// Create a new datasource for set filtered datasource
var orderAmountQueryDataSource = new kendo.data.DataSource({
pageSize: 15,
});
orderAmountQueryDataSource.data(orderAmountQuery.data);
// set grid2's data source with filtered dataSource
var grid2 = $("#Grid2").data("kendoGrid");
grid2.setDataSource(orderAmountQueryDataSource);
Your main answer is here :
is it possible to copy a grid datasource to a new datasource, a new datasource that loads all data?
But for your case which you need to do filtering as well you can use this:
Add your second grid in CSHTML:
<div id="MySecondGrid"></div>
Use the following Javascript:
// Get the first datasource
var ds1 = $("#Orders").data("kendoGrid").dataSource;
// Filter the second datasource
var ds2 = $.grep(ds1._data, function (item) { return item.OrderAmount > 100; });
ds2.serverPaging = false;
// Set the second datasource
$("#MySecondGrid").kendoGrid({
dataSource: ds2
});
I have a kendo grid and one of columns ("status" column) is set as filter multi checkbox. In the middle tier I call an api to get data by given page size and page, by this way to implement server side paging.
But the problem is that the filter multi checkbox only contains values that are in one page. For example, the api can return maximum 1000 records at a time, the filter multi checkbox only showing the items that in this 1000 records. Let's say total there are 20000 and there are 3 different status - "Delay", "Pending", "Processed". The first 1000 records only has "Delay" status. Then on the grid, the filter multi checkbox only display one status option- "Delay".
How can I show all those 3 statuses? Maybe I can create another api to return all status, but how to modify the datasource so that it will show all status?
Below are the code snap.
UI:
#(Html.Kendo().Grid<ExceptionsPerGroup>()
.Name("gridBatchDetail")
.Columns(columns =>
{
columns
.Bound(p => p.SnapshotHeader_Account_AccountNumber)
.Filterable(pfs => pfs.Extra(false))
.Title("LOAN NUMBER");
columns
.Bound(p => p.Borrower_BorrowerName_FullNameToBeParsed)
.Filterable(pfs => pfs.Extra(false))
.Title("BORROWER NAME");
columns
.Bound(p => p.PaymentHeader_ReportedPaymentAmount)
.Title("PAYMENT AMOUNT").Format("{0:C}");
columns
.Bound(p => p.CurrentStatus_PaymentStatus)
.Filterable(fs => fs.Multi(true))
.Title("STATUS");
columns
.Bound(p => p.CurrentExceptionTypeCode)
.Filterable(fs => fs.Multi(true))
.Title("EXCEPTION REASON");
columns
.Bound(p => p.CurrentStatus_CurrentAssignee)
.Filterable(pfs => pfs.Multi(true))
.Title("ASSIGNED TO");
})
.Pageable()
.Sortable()
.Filterable(pfs => pfs
.Operators(o => o.ForString(s => s.Clear()
.Contains("Contains")
)))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(true)
.PageSize(20)
.Read(read => read.Action("GetPaymentsList", "FileSummary").Data("getURLString"))
)
.ClientDetailTemplateId("batchDetailsTemplate")
)
Controller:
public JsonResult GetPaymentsList([DataSourceRequest]DataSourceRequest request, string uri)
{
try
{
var myUri = new Uri(uri);
var fileKeyString = HttpUtility.ParseQueryString(myUri.Query).Get("fileKey");
var batchKeyString = HttpUtility.ParseQueryString(myUri.Query).Get("batchKey");
Guid? fileKey = new Guid(fileKeyString);
Guid? batchKey = new Guid(batchKeyString);
var fileBatchPaymentTransactionsResponse = ApiHelper.GetBatchDetailByFileKeyAndBatchKey(fileKey, batchKey, request.PageSize, request.Page, request);
List<ExceptionsPerGroup> listOfPayments = null;
if (fileBatchPaymentTransactionsResponse.ListResults != null)
{
listOfPayments = DataMapper.MapperPaymentTransactionDataToExceptionsPerGroupsModel(fileBatchPaymentTransactionsResponse.ListResults);
}
var result = new DataSourceResult()
{
Data = listOfPayments,
Total = (int)fileBatchPaymentTransactionsResponse.TotalRecords
};
return Json(result);
}
catch (Exception ex)
{
logger.LogMessage("FileSummary/GetPaymentsList", EnumLogLevel.Severe, "EXCEPTION:", ex);
}
return null;
}
I solve this problem by adding an FilerMenuInit event handler, in this handler ajax call a method to retrieve all the Status values.
UI:
#(Html.Kendo().Grid<ExceptionsPerGroup>()
.Name("gridBatchDetail")
.Events(e=>e.FilterMenuInit("InitFilterMenu"))//add this event
.Columns(columns =>
....
<script type="text/javascript">
function InitFilterMenu(e) {
if (e.field === "CurrentStatus_PaymentStatus") {
var filterMultiCheck = this.thead.find("[data-field=" + e.field + "]").data("kendoFilterMultiCheck");
var url = '#Url.Action("GetStatusListForGrid", "FileSummary")';
$.getJSON(url, { }, function (result, status, xhr) {
filterMultiCheck.container.empty();
filterMultiCheck.checkSource.data(result);
filterMultiCheck.createCheckBoxes();
});
}
}
I have a kendo autocomplete box, which is bound to remote data.
whenever i type into the search box, my default Ajax loading animation is pop outs
i did some googling and found-->>> this
which says to include global: false in read to suppress this global ajax behavior
how can this be done in MVC wrapper?
#(Html.Kendo().AutoComplete()
.Name("productAutoComplete")
.DataTextField("ProductName")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetProducts", "Home");
})
.ServerFiltering(true);
})
)
I'm using the same scenario. After searching the internet for hours only answer on my hand was "You can't do it with wrappers. You have to initiate the autocomplete by js." But then I saw another solution for another product which make sense.
Here's what I did for my project:
In main js file;
var ajaxStartActive = true;
$(document).ajaxStart(
function () {
if (ajaxStartActive)
$loading.show();
}).ajaxStop(
function () {
$loading.hide();
});
Using with AutoComplete;
#(Html.Kendo().AutoComplete()
.Name("productAutoComplete")
.HtmlAttributes(new { onfocus = "ajaxStartActive = false;", onblur = "ajaxStartActive = true;" })
.DataTextField("ProductName")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetProducts", "Home");
})
.ServerFiltering(true);
})
)
I hope it helps
I have a small Kendo Grid, set up as below. In an inccredibly mysterious fashion, the Controller action for "Add New", i.e. BatchCreate is only invoked if when you click another command button after clicking "Add New". E.g. a) Click "Add New", nothing at all happens. b) Reload the page, and click "Add New", and have nothing happen, then click "Save Changes", then the BatchCreatemethod is finally invoked.
My grid looks like this, copied nearly straight from an example of theirs:
#(Html.Kendo().Grid<LocationIndexItem>()
.Name("index-grid")
.Columns(columns =>
{
columns.Bound(p => p.Name);
columns.Bound(p => p.IsActive).ClientTemplate(
"<input type='checkbox' value='#= IsActive #' " +
"# if (IsActive) { #" +
"checked='checked'" +
"# } #" +
"/>").Width(70);
columns.Bound(p => p.Remarks);
columns.Command(cmd => cmd.Destroy());
})
.ToolBar(toolbar =>
{
toolbar.Create();
toolbar.Save();
})
//.Events(e => e.Edit("gridEdit"))
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Filterable()
.Pageable()
.Scrollable()
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Batch(true)
.PageSize(20)
.Events(events => events.Error("errorHandler"))
.Model(model => model.Id(p => p.Id))
.Read(read => read.Action("Read", "Location"))
.Update(update => update.Action("BatchUpdate", "Location"))
.Create(create => create.Action("BatchCreate", "Location"))
.Destroy(destroy => destroy.Action("BatchDelete", "Location"))
)
)
Another grid exactly the same, except for one extra field, works perfectly.
JUST IN: Filtering the grid with the following code seems to cause the above behaviour. When I comment the commented line, $("#ParkadeId").change() out, the grid behaves as normal:
$(function() {
$("#ParkadeId").change(function () {
var value = $(this).val();
var grid = $("#index-grid").data("kendoGrid");
if (value) {
grid.dataSource.filter({ field: "ParkadeId", operator: "eq", value: parseInt(value) });
} else {
grid.dataSource.filter({});
}
});
//$("#ParkadeId").change();
});
It would seem setting a filter on a Kendo grid breaks the Add New functionality.
According to Kendo Ui Support Forum - this is expected behaviour when the filtering / sorting are applied on the client side, because when the new record is created outside the current view, it cannot be edited.
Possible solutions is to enable server sorting / filtering or implement custom "Add record" button which first clears the data source current filter and sort and then add new record using grid API.
This is an example of a function that clears current filters and sorting before adding a new record:
function createNew() {
var grid = $("#grid").data("kendoGrid");
grid.dataSource.filter({});
grid.dataSource.sort({});
//add record using Grid API
grid.addRow();
}
I found a good solution to this in the Kendo forums:
What I did was create a zero filter which accepts data with primary key equal to zero (since a row you just added with have zero as its primary key), and anywhere I need to set a custom filter I just include the zero filter as well:
var zeroFilter = {
field: "FieldID",
operator: "eq",
value: 0
};
function filterData() {
var ds = $("#Grid").data("kendoGrid").dataSource;
ds.filter({
logic: "or",
filters: [
{
field: "MyField",
operator: "eq",
value: someValue
},
zeroFilter
]
});
}
This can be done by custom "create" toolbar
$("#grid").kendoGrid({
...
toolbar: [{
name: "my-create",
text: "Add new record"
}],
..
)};
on load
$(".k-grid-my-create", grid.element).on("click", function(e) {
var grid = $("#grid").data("kendoGrid");
grid.dataSource.filter({});
grid.dataSource.sort({});
//add record using Grid API
grid.addRow();
});
i'm using CakePHP with a datepicker and a timepicker. In my CakePHP aplicattion i use
$this->Js->get('#tes')->event('change', $this->Js->request
to populate different dropdown lists according to the choices.
but when i choose an element of a dropdownlists and my request (js->get(#tes) ...) are made, my date/time picker the are crazy:
The datepicker not get with the current date selected.
The TimePicker, whenever I try to change the time (it does not allow) and
always comes back to the previous hour.
how can i resolve my problem?
is there any way in javascript file, check if a request was made "change" and reset the time / datepicker?
MY JAVASCRIPT FILE TO TIMEPICKER
(function($) {
$(document).ready(function() {
$('#timepicker').timepicker();
});
})(jQuery);
MY JAVASCRIPT FILE TO DATEPICKER
(function($) {
$(document).ready(function() {
var today = new Date(),
t = today.getDate() + "-" + (today.getMonth() + 1) + "-" + today.getFullYear();
$("#dp3").datepicker(
{
format: 'yyyy-mm-dd'
}
).on('show', function(e) {
$("#dp3").datepicker('setValue', t);
});
if (document.getElementById("date")) {
document.getElementById("date").value = document.getElementById("date").defaultValue = t;
}
});
})(jQuery);
CODE IN MY VIEW THAT CHANGE DROPDOWNLISTS
$this->Js->get('#example')->event('change', $this->Js->request(array(
'controller' => 'Example',
'action' => 'getmylist'
), array(
'update' => '#example2',
'async' => true,
'method' => 'post',
'dataExpression' => true,
'data' => $this->Js->serializeForm(array(
'isForm' => true,
'inline' => true
))
)));
I just can not explain what happens to the datepicker. he turns around at the time. back to 1928 and not to the current date.
Thanks