Clear selection in Kendo Grid Detail Template without clearing the selected row - asp.net-mvc

I have a Kendo Grid with detailed template, a grid within grid, and I want only one row to be selected each time. For instance, if a row is selected and I expand it, showing the inner grid, then I select one row from the inner grid, the row in the outer grid always stays selected. Now I have two selected rows in the grid, one selected in the outer grid (the master row) and also the row in the inner grid.
Can I grab some event that would imitate a sort of "OnLeave" event?
I have been going through the Kendo Documentation and the only thing I can come up with is trying to grab something within the Change-event. However I havenĀ“t been able to find out how to clear all selections in both grids without clearing also the selected row I clicked last (either in the inner or outer grid).
Anyway, any help is well apprectiated on this silly matter :)
My View
#(Html.Kendo().Grid<SomeModel>()
.Name("SomeGrid")
.Columns(c =>
{
// some columns (abbreviated)
})
.Selectable(s => s.Enabled(true).Mode(GridSelectionMode.Single).Type(GridSelectionType.Row))
.ClientDetailTemplateId("someTemp")
.Events(events => events.DataBound("dataBound").Change("onSomeGridChange"))
.DataSource(d => d.Ajax().Model(model => model.Id(p => p.SomeId)))
)
<script id="someTemp" type="text/kendo-tmpl">
#(Html.Kendo().Grid<SomeObject>()
.Name("grid_#=SomeId#")
.Columns(c =>
{
// some columns (abbreviated)
})
.Selectable(s => s.Enabled(true).Mode(GridSelectionMode.Single).Type(GridSelectionType.Row))
.Events(events => events.Change("onSomeGridChange"))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GetSomeData", "Controller", new { blNumber = "#=SomeId#" })))
.ToClientTemplate()
)
Then my script:
function onDerpChange(e) {
e.preventDefault();
var fff = e.sender;
// How could I clearselection on all other rows than the one I selected last?
var selectedRows = this.select();
var selectedDataItems = [];
for (var j = 0; j < selectedRows.length; j++) {
var ddataItem = this.dataItem(selectedRows[j]);
selectedDataItems.push(ddataItem);
}
}

You can use attach 'select' event handlers to all those grids (the outer and the inner one) to a single event which clears all the other selected rows.
The event handler should look something like this:
function onRowSelect(){
var currentlySelected = this.select();
$('.k-grid tbody>.k-state-selected').not(currentlySelected).removeClass('k-state-selected')
}

Related

Kendo MVC TreeList not Rendering from Initial BindTo

My MVC ViewModel contains the initial list of records to be displayed within my Kendo TreeList. However, the TreeList is NOT rendering the initial list...and I don't understand why.
REQUIREMENTS:
If initial records exist...display them
The READ ACTION CANNOT be executed on the initial render (other controls manage that later)
For other Kendo controls, you set:
AutoBind(false)
BindTo(Model.MyCollectiom)
...and the READ ACTION does not execute. But the TreeList is failing at the moment.
MY RAZOR LOOKS LIKE:
At initial render records DO EXIST (see image below)
#(Html.Kendo().TreeList<DeviceHierarchyDataItem>()
.Name("treeTarget")
.Columns(columns =>
{
columns.Add().Field(e => e.DisplayName)
.TemplateId("tmplDisplayName")
.Title(" ");
})
.BindTo(Model.TargetDevices)
.AutoBind(false)
.DataSource(dataSource => dataSource
.Read(read => read.Action("find", "devicehierarchy", new { Area = "" })
.Data("window.etp.pageController.getFilter"))
.ServerOperation(false)
.Model(m =>
{
m.Id(f => f.Id);
m.ParentId(f => f.ChildOf);
m.Expanded(true);
m.Field(f => f.DisplayName);
}))
.Sortable())
Strangely enough the TreeList MVC control doesn't support binding to local data...
At least not in july 2018...
The recommendation is to use the jquery control instead.
And then convert the data from the Model to a json string:
$(document).ready(function () {
var dataSource = new kendo.data.TreeListDataSource({
data: #Html.Raw(Json.Encode(#Model.TargetDevices)),
schema: {
model: {
id: "Id",
parentid: "ChildOf",
expanded: true
}
}
});
I hope it helps!

Telerik MVC Grid Inline editing requires page refresh to display changes

I have a Telerik MVC Grid where I am updating the rows inline (updating name column, number column is uneditable)
#Html.Kendo().Grid(Model.Employees)
.Name("EmployeeGrid")
.Columns(col =>
{
col.Bound(o => o.EmployeeNumber);
col.Bound(o => o.Name).Width(250);
col.Command(command => { command.Edit(); });
})
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Events(e => e.RequestEnd("onGridDataSourceRequestEnd"))
.Model(model =>
{
model.Id(o => o.EmployeeNumber);
model.Field(o => o.EmployeeNumber).Editable(false);
})
.Update(update => update.Action("EditingInline_Update", "EmployeeUpdate"))
.ServerOperation(false)
)
.Render();
function onGridDataSourceRequestEnd(e) {
if (e.type == "update") {
console.log('I am inside Update');
$("#EmployeeGrid").data("kendoGrid").dataSource.read();
}
}
My problem is that above code updates the record by calling action EmployeeUpdate when I click on Update button in the grid. However, that change doesnt immediately reflect in the grid even though I am calling datasource read in JS function. Console shows "I am inside Update" but doesnt refresh grid. If I refresh the page, I do see the update row.
Please let me know what am I missing. Thank you.
You should not have to refresh/reload your grid when doing an update, you just have to return the updated record from the controller and grid-widget will take care of the rest!
Please checkout telerik demo-page
The most common error I do is forgetting to return a datasourceresult:
.ToDataSourceResult(request,ModelState)
Telerik normally returns the same model that are sent in to the update, but I normally returns the same object that the read function returns (if read does something I'll get that on the updated record too).
Probably you should try refreshing the grid with refresh() function:
function onGridDataSourceRequestEnd(e) {
if (e.type == "update") {
console.log('I am inside Update');
$("#EmployeeGrid").data("kendoGrid").dataSource.read();
// add this line
$("#EmployeeGrid").data("kendoGrid").refresh();
}
}
Note that read() function in dataSource only reload data source by request to the server, the grid contents still not changed before using refresh().

Multiselect list in Kendo Grid inline editing

I need to use multiselect list in kendo grid (inline editing) so that user can select multiple values from the list per row.
Following are my requirements:
At the time of display, kendo grid should show comma separated list of all the selected values.
At the time of Add, kendo grid should show multiselect list and allow to select multiple values.
At the time of Edit, kendo grid should show multiselect list with already selected values. User should be able to modify the select and add/remove items from the list.
When user clicks on update/save button, selected values from multiselect list should be available in code behind (in update ajax action) along with id of row.
Following what I do as of now:
I am taking an approach similar to using a drop down list in kendo inline grid.
I have created an Editor Template for displaying multiselect at the time of add/edit.
Following is the code:
#model List<Namespace.CompanyConnector>
#using Kendo.Mvc.UI
#(Html.Kendo().MultiSelectFor(c=>c)
.Name("company_connector_id")
.DataTextField("connector_name")
.DataValueField("company_connector_id")
.Placeholder("Select connector...")
.AutoBind(false)
.Value((List<int>)ViewData["SelectedValues"])
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCompanyConnectors", "BrandConnector");
})
.ServerFiltering(true);
})
)
#Html.ValidationMessageFor(m => m)
Explanation: I bind a list of model class to the multiselect and set data source in the read action. For selecting the selected values at the time of edit, I have created a function that returns the ids of selected values and put that in View Data in the read action.
I've used this Editor template in my Index page as following code:
#{Html.Kendo().Grid<Cee.DomainObjects.DomainObjects.BrandConnector>()
.Name("BrandConnectorGrid")
.Filterable()
.Events(e => e.Edit("onEdit"))
.DataSource(dataSource => dataSource
.Ajax()
.Events(e => e.Error("error_handler").RequestEnd("onRequestEnd"))
.ServerOperation(false)
.Model(model =>
{
model.Id(p => p.brand_id);
model.Field(e => e.CompanyConnectorList).DefaultValue(new
List<Cee.DomainObjects.DomainObjects.CompanyConnector>());
})
.Read(read => read.Action("_AjaxBinding", "BrandConnector",new{companyID = 0 }).Type(HttpVerbs.Post))
.Update(update => update.Action("_UpdateBinding", "BrandConnector").Type(HttpVerbs.Post)))
.Columns(columns =>
{
columns.Bound(c => c.brand_connector_id).Width(0).Hidden(true);
columns.Bound(c => c.company_id).Width(0).Hidden(true);
columns.Bound(c => c.brand_id).Width(0).Hidden(true);
columns.Bound(u => u.brand_name).Title("Brand").Width("18%").HtmlAttributes(new { #class = "brkWord", #readonly = "readonly" });
columns.ForeignKey(u => u.connector_name, Model.CompanyConnectorList, "company_connector_id", "connector_name").Title("Connector").Width
("16%").HtmlAttributes(new { #class = "brkWord" }).EditorTemplateName("company_connector_id");
columns.Command(p => p.Edit().Text("Edit").HtmlAttributes(new { #title = "Edit" })).Width("16%").Title("Edit");
})
.Editable(editable => editable.Mode(GridEditMode.InLine).CreateAt(GridInsertRowPosition.Top))
.Pageable(pageable => pageable.Refresh(true).PageSizes(GlobalCode.recordPerPageList).ButtonCount(GlobalCode.PageSize).Input(true).Numeric(true))
.HtmlAttributes(new { #class = "dynamicWidth" })
.Sortable(sorting => sorting.Enabled(true))
.Render();
}
Explanation: I've used ForeignKey. Bound it to the string column "connector_name". Connector_name is a comma separated list of IDs that I send from controller. Editor template is used here.
Issue: It works fine at the time of View/Display in Index but Edit does not show selected value. Also we do not get updated value in code behind on update click.
Is this correct way of implementing multiselect list or do I need to bind a collection property as a column in grid?
If I bind a collection property as a column then how would I be able to show comma separated string at the time of display?
Try below code:
function onEdit(e) {
var multiselect = $("#YourMutliselectDropdown").data("kendoMultiSelect");
var IDArray = [];
$(e.model.propertyName).each(function (index) {
var ID = e.model.propertyName[index].id;
IDArray.push(ID);
});
multiselect.value(IDArray);
}
I assume that propertyName is List of your collection and it contains id as property.
try it:
c.Bound(p => p.CompanyConnectorList).ClientTemplate("#= connectorsToString(data)#").EditorTemplateName("company_connector_id");
and js:
function connectorsToString(data) {
var list = data.company_connector_id;
var result = "";
for (var i = 0; i < list.length; i++) {
result += list[i].Name + ';';
}
return result;
}

kendo UI Grid MVC initial page

I am using Kendo UI Grid. Is there a way to start the grid at a different page than the first page?
i want to set initial page number to '3' every time i open the grid.
I would suggest you to set the AutoBind property of the Grid to false and when the document ready event occurs use the page method of the dataSource (which is actually what the pager.page invokes).
$('#MyGrid').data().kendoGrid.dataSource.page(3);
The Data function which you used is intended for slightly different purposes :)
I use an ajax datasource, and I needed to do:
Set the AutoBind to false
Set the total records in the data source
Call by javascript the page() method of the data source
Here is a fragment of my view (I use razor):
Notes: In the action I set two values in the ViewBag:
ViewBag.InitialPage: Initial page to show
ViewBag.Total: Total record count
.
#{
int initialPage = (int)ViewBag.InitialPage;
int totalPages = (int)ViewBag.Total / 20;
}
#(Html.Kendo().Grid<YourModelClass>
()
.Name("gridMain")
.Columns(columns =>
{
//Todo: Add your columns
})
.Pageable(p => p.Refresh(true).Info(true).Input(true).ButtonCount(6).Numeric(true))
.Sortable()
.Scrollable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("YourAction", "YourController"))
.Total(ViewBag.Total) //Set the total record count
)
.AutoBind(false)
)
<script type="text/javascript">
$(function () {
var initialPage = #initialPage;
$('#gridMain').data().kendoGrid.dataSource.page(initialPage);
})
</script>

How to format the row based on condition in kendo ui mvc grid

I am working on asp.net mvc. I am trying to display list of messages in a Kendo mvc ui grid.
I have written the code like,
Html.Kendo().Grid((List<messages>)ViewBag.Messages))
.Name("grdIndox")
.Sortable(m => m.Enabled(true).SortMode(GridSortMode.MultipleColumn))
.HtmlAttributes(new { style = "" })
.Columns(
col =>
{
col.Bound(o => o.RecNo).HtmlAttributes(new { style = "display:none" }).Title("").HeaderHtmlAttributes(new { style = "display:none" });
col.Bound(o => o.NoteDate).Title("Date").Format("{0:MMM d, yyyy}");
col.Bound(o => o.PatName).Title("Patient");
col.Bound(o => o.NoteType).Title("Type");
col.Bound(o => o.Subject);
}
)
.Pageable()
.Selectable(sel => sel.Mode(GridSelectionMode.Single).Type(GridSelectionType.Row))
.DataSource(
ds => ds.Ajax().ServerOperation(false).Model(m => m.Id(modelid => modelid.RecNo))
.PageSize(10)
//.Read(read => read.Action("Messages_Read", "Msg"))
)
.Events(ev => ev.Change("onSelectingGirdRow"))
)
and i have the field in the table like IsRead-boolean type. so if the message is unread message then i need to format that record with bold font. I have used clientTemplates but with that i am able to format only particular cells i want format entire row. Please guide me.
as Sanja suggested you can use the dataBound event but it will be better to cycle through the tr elements (the rows). Also I assume that you will need the related dataItem to check if the property that indicates if the message is read.
e.g.
dataBound: function ()
{
var grid = this;
grid.tbody.find('>tr').each(function(){
var dataItem = grid.dataItem(this);
if(!dataItem.IsMessageRead)
{
$(this).addClass('someBoldClass');
}
})
}
You can use dataBound event to change your rows.
dataBound: function ()
{
$('td').each(function(){
if(some condition...)
{
$(this).addClass('someBoldClass')}
}
})
}
There is another way to do that.It's called RowAction.
.RowAction(row =>
{
if (condition)
{
row.HtmlAttributes["class"] = "someBoldClass";
}
})
Please note that the RowAction is available only for rows that are rendered on server side. So in your case, you can use RowAction as an alternative to DataBound.

Resources