I have a kendo grid, in which I want to make a column editable.
Check the below code what I have done
Html.Kendo().Grid(Model.MyGridData)
.Name("MyGridName")
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Events(e => e.RequestEnd("FormatDates"))
.ServerOperation(true))
.Columns(columns =>
{
foreach (var item in Model.GridHeaderCollection)
{
if (item.IsEditable)
{
columns.Bound(item.Name)
.ClientTemplate("# if(" + item.Name + "){#<input id='checkbox' onclick='grdChkBoxClick(this); ' class='chkboxApprove' type='checkbox' checked='checked' value='#=" + item.Name + "#' chkValue='decline_#=" + item.Name + "#' />#}else{#<input id='checkbox' onclick='grdChkBoxClick(this); ' class='chkboxApprove' type='checkbox' value='#=" + item.Name + "#' chkValue='decline_#=" + item.Name + "#' />#}# ")
.Title(item.Name);
}
else
{
columns.Bound(item.Name).Title(item.DisplayName).Format(GridDataFormat);
}
}
}).Events(e => e.DataBound("AttachmentActionFlyOutBound"))
So when I check/ uncheck the checkbox it should reflect in the data source
As I checked Editable is available for the entire model. I need it for a single column.
I have seen some post which uses schema, didn't get how to implement the same here
Related
I am trying to create a class that create a generic kendo TreeView that the tree can have items with checkbox and items without checkbox.
So, I created a class with the flowing c'tor:
constructor(checkable: boolean = false) {
// Create the treeview options
const treeViewOptions: kendo.ui.TreeViewOptions = {
checkboxes: {
checkChildren: true,
template: "# if (item.level() > 0) { #" +
"<input type='checkbox' #= item.checked ? 'checked' : '' #>" +
"# } #"
},
// ... The rest of the treeViewOptions ...
}
Now, all items that their item.level==0 are without checkbox.
I want that if the parameter "checkable" of the c'tor is false, than all the items in the tree will not have checkboxes. I didn't know how to pass the "checkable" parameter into the template. I wanted something like this:
checkboxes: {
checkChildren: true,
template: "# if (checkable && item.level() > 0) { #" +
"<input type='checkbox' #= item.checked ? 'checked' : '' #>" +
"# } #"
},
Please help me with that and if you think that there is more elegant way to do that I will be happy to hear.
Thanks
You could make the template be an anonymous function and have it emit different template strings depending on constructor argument.
template: function () {
if (checkable) {
return ... template string that allows checkboxes at item level > 0 ...
} else {
return ... simpler template string that has no checkboxes anywhere ...
}
}
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();
});
}
}
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.
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 am using telerik grid for mvc with ajax custom binding and its running ok, but the problem is when i apply the grouping it sends it ruins the grid.
Before Grouping
After Grouping
The client side code looks like
colums.Bound(o => o.TO).Title("To").Groupable(false).HtmlAttributes(new { style = "text-align:center" }).Width(150);
colums.Bound(o => o.CanChange).Hidden(true);
colums.Bound(o => o.PlanHospitalID).Hidden(true).HtmlAttributes(new { #class = "planhospital" });
if ((Model.GeoLocationType == SalesEnum.Region.ToString()))
{
colums.Bound(o => o.RMAcompanies).Groupable(false).Title("Join(RM)").ClientTemplate("<input class='rmjoin' name='RMID' type='checkbox' value='" + Model.DesignationID + "' <#=RMAcompanies? checked='checked' : '' #> <#=CanChange? '' : disabled='disabled' #> /><input type='hidden' name='PlanHospitalID' value='<#= PlanHospitalID#>'/>");
}
colums.Bound(o => o.SMCanChange).Hidden(true);
if (Model.GeoLocationType == SalesEnum.Zone.ToString())
{
colums.Bound(o => o.SMAcompanies).Title("Join(SM)").Groupable(false).ClientTemplate("<input class='smjoin' type='checkbox' name='SMID' value='" + Model.DesignationID + "' <#= SMAcompanies?checked='checked':'' #> <#=SMCanChange? '' : disabled='disabled' #> /><input type='hidden' name='PlanHospitalID' value='<#=PlanHospitalID#>'/>");
}
colums.Bound(o => o.Participants).Groupable(false);
I hava been in the trouble for several days.
I got the cause now...
For the ajax controller, you must:
1--retrieve and send back all the data, not only the pagesize;
2--return the View(model) not the json format.
Hope it can help you out.