kendo grid shared data source - kendo-ui

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
});

Related

How to get all values for kendo grid filter multi checkbox when implement server side paging

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();
});
}
}

What's missing in this Kendo Grid / DropDownList combination?

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.

Suppress global ajax in kendo autocomplete MVC

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

Kendo toolbar AddNew button doesn't work when the grid is filtered

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();
});

Embed a View using AJAX

I have a view with one argument, and a set of exposed filters. When the user filters the view, the form is submitted using Ajax, and the filters are appended to the url using location.hash.
My goal is to filter the view upon initial page load, if the filters are present in the location.hash.
Currently, I'm loading the view through an Ajax callback, which works perfectly fine. But the big problem is that Ajax for the view doesn't work.
This is the callback that loads the View.
// Load the view object.
$view = views_get_view('taxonomy_term');
$view->set_display('page');
$view->set_use_ajax(TRUE);
// Pass the current tid as the argument.
$view->set_arguments(array($tid));
// Set the current page.
$view->set_current_page($page);
// Set the exposed filters.
$view->get_exposed_input();
// Execute.
return $view->execute_display();
When I navigate directly to that callback, everything works. But not when I load it through Ajax.
Any ideas?
Update:
It seems that Drupal.behaviors.ViewsAjaxView() doesn't execute for some reason. If I execute it manually, everything works.
Ok, so I've found the answer.
Instead of loading the View from my own callback, I'm now loading the View from the regular ajax callback.
On my page, I create the view object, and add the configuration to Drupal.settings.
$view = views_get_view('taxonomy_term');
$view->set_display('page');
$view->set_use_ajax(TRUE);
$view->set_arguments(array($tid));
$settings = array(
'views' => array(
'ajax_path' => url('views/ajax'),
'ajaxViews' => array(
array(
'view_name' => $view->name,
'view_display_id' => $view->current_display,
'view_args' => check_plain(implode('/', $view->args)),
'view_path' => check_plain($_GET['q']),
'view_base_path' => $view->get_path(),
'view_dom_id' => 1,
'pager_element' => $view->pager['element'],
),
),
),
);
drupal_add_js($settings, 'setting');
views_add_js('ajax_view');
Then I load my js, which adds the current filter from the location.hash to the settings. And finally, loads the View.
var data = {};
// Add view settings to the data.
for (var key in Drupal.settings.views.ajaxViews[0]) {
data[key] = Drupal.settings.views.ajaxViews[0][key];
}
// Get the params from the hash.
if (location.hash) {
var q = decodeURIComponent(location.hash.substr(1));
var o = {'f':function(v){return unescape(v).replace(/\+/g,' ');}};
$.each(q.match(/^\??(.*)$/)[1].split('&'), function(i,p) {
p = p.split('=');
p[1] = o.f(p[1]);
data[p[0]] = data[p[0]]?((data[p[0]] instanceof Array)?(data[p[0]].push(p[1]),data[p[0]]):[data[p[0]],p[1]]):p[1];
});
}
$.ajax({
url: Drupal.settings.views.ajax_path,
type: 'GET',
data: data,
success: function(response) {
var viewDiv = '.view-dom-id-' + data.view_dom_id;
$('#content > div.limiter').html(response.display);
// Call all callbacks.
if (response.__callbacks) {
$.each(response.__callbacks, function(i, callback) {
eval(callback)(viewDiv, response);
});
}
},
error: function(xhr) {
$('#content > div.limiter').html('<p id="artist-load-error">Error text.</p>');
$('#block-request-0').hide();
},
dataType: 'json'
});
This way, the view loads through the regular flow, and everything works as expected =)

Resources