If I specify "SortMode.Mixed" for a Grid's "SortMode" (via the .Sortable fluent method), the sort mode in the JavaScript initializer is set to "multiple" instead. This can even be seen on the MVC Demo page here: https://demos.telerik.com/aspnet-mvc/grid/sorting (the "mixed" demo behaves just like "multiple").
In the Kendo MVC source code for 2022.1.301, the GridSortableSettings.Serialize method appears to use the following logic:
if (SortMode != GridSortMode.SingleColumn)
{
json["mode"] = "multiple";
}
I'm using the ClientTemplate-Feature to render buttons for CRUD-actions in grids. For one entity I have to use a TreeList instead of a Grid due to parent-child relations. It would be great if I could use the same templates I use for the grid for the treelist as well.
Example:
columns.Bound(x => x.UserName)
.ClientTemplate("<a href='" + Url.Admin().Account() + "/#= Id#/edit'>#= UserName #</a>")
.Width(300);
Please note the following MVC code:
Bug 1: The Window should have the top set by the Top() method. It does not.
Bug 2: The Window should have the top set by the HtmlAttributes() method. That does not work either.
Bug 3: The scrollable method also does nothing to the window. So this entire line seems to be omitted.
Bug 4: The window is supposed to be centered by the Kendo native code. It isn’t. The recurring editor div element is not shown until after the window centers. So the window generates, centers on the screen, then the recurring DIV is shown which expands the window downwards, then the window is shown. This makes it go off the bottom of the screen. I didn’t need vertical center anyways so I fixed this by setting the top to 40px. Which is when I ran into the above issues. However if I was not doing this, the center() issue would still be there. I fixed this in JavaScript on the event’s edit event.
I have a Kendo Notification component on my page. When the page loads, it is possible a notification needs to show immediately. This fails because the Notification component is not ready yet. Even putting this message show inside a document.ready() call does not work. There’s no rendered event on this component to know when Kendo has it added to the DOM and it is accessible. So I ended up creating an array of messages to show. And running a setInterval block on page load until it is ready to go. Then clearing the interval and message array. It’s a work around but it is hacky and it would be better if I could subscribe to an event that tells me when the notification component can be used.
My understanding after talking to support is that a grid with a popup editor has code behind the scenes that stops adverse scrolling behavior when the popup window closes. However, under certain circumstances, this doesn't work if you have a grid nested in your popup editor that also has a popup editor. As it was described to me, this "behavior is not directly related to the Grid, but the Kendo Window. Generally, it provides the preventScroll property, but I am afraid this scenario is more complex due to the window being internally embedded into the Grid".
The exact scenario I found was that if you shrink you browser window small enough that you need to use some scrolling, scroll down your grid a little, then do something to cause the popup editor to open. Scroll down again to get to your nested grid, open that popup editor, then close it. The browser then auto scrolls to the top.
I was given this code to fix the issue (and it DOES fix it):
<script>
kendo.ui.Grid.fn._destroyEditableOrg = kendo.ui.Grid.fn._destroyEditable;
kendo.ui.Grid.fn._destroyEditable = function () {
var that = this;
if (that._editContainer) {
var kw = that._editContainer.data().kendoWindow;
kw.setOptions({
modal: false
});
}
that._destroyEditableOrg();
};
</script>
The problem is that these fields aren't documented... I would never have figured this out on my own. So my feature request is that either this behavior is fixed or these properties exposed from the Grid settings.
-Steven
PS: For Telerik, the original ticket was 1589389.
I have a cshtml page that uses Kendo UI ASP.NET MVC that does the following:
The view contains one or more grid widgets (the number depends on how many result types were requested) and each grid is set up to export Excel.
The problem is that when window.open() is used to open a new tab, the browser history state is null and the window.location.href is empty with the browser location showing "about:blank". For Chrome and Firefox, this does not cause any issues when exporting excel for the grid. However, when using Edge with this situation, when the Export to Excel grid toolbar button is clicked and the onExportExcel event is fired, the browser Open or Save dialog prompt is displayed but the active tab (the one that contained the grid) closes. This behaviour is very undesireable. The ProxyUrl grid excel option does not fire since Edge supports javascript file saving.
A workaround for this situation is to forcibly set the new tab window object location href by using the window.history.pushUpdate function. A code snippet is included below.
let dataModel = {Id = 123571113, Name="jason bourne"}; let jsonModel = JSON.stringify(dataModel); let curDate = new Date(); let targetUrl = '@Url.Action("Reports", "Report", new { @area = "Reports" })'; let targetWindowName = "something meaningful" + " " + curDate.toISOString();//add datetime stamp to avoid issue where you cannot open a window with the same name as the current window. let html = "some html content to provide a temporary message to your audience"; let targetWindow = window.open(targetUrl, targetWindowName); if (targetWindow !== null && targetWindow !== undefined) { targetWindow.document.write(html); targetWindow.document.close(); // to finish loading the page targetWindow.document.title = targetWindowName; //attempt to forcibly update the URL in the history and target window location to fix problem with grid export to excel on Edge browser let targetWindowHistoryHref = window.location.href; if (oModel.BuildingDesigns !== null && oModel.BuildingDesigns !== undefined && oModel.BuildingDesigns.length > 0) { targetWindowHistoryHref += "?oBuildingDesignId=" + oModel.BuildingDesigns[0].ObfuscatedBuildingDesignId + "&BuildingDesignName=" + oModel.BuildingDesigns[0].BuildingDesignName; } else { targetWindowHistoryHref += "?" + oModel.Target; } targetWindow.history.pushState(null, null, targetWindowHistoryHref); } $.when( $.ajax({ type: "POST", dataType: "html", // this is the data type expected to be returned from the controller method contentType: "application/json", // this is the content type expected by the controller method url: targetUrl, data: jsonModel, beforeSend: function() { console.log(".... submitting report request"); athena.loader.loading("submitting report request"); }, success: function(response) { athena.loader.stopLoading(); if (debugLevel > 2) { console.log(".... response = " + response + " : ", response); } //attempt to populate the target browser tab with the response try { console.log(".... attempting to open a browser tab and populate it with the HTML response object"); console.log(".... targetWindow = " + targetWindow); //will trigger popup blockers :: targetWindow = window.open("", oModel.Target); if (targetWindow !== null) { if (response === null || response === undefined) { targetWindow.document.body.innerHTML = ''; } else { //completely replace the existing document (not just the innerhtml) targetWindow.document.open(); targetWindow.document.write(response); targetWindow.document.close(); targetWindow.document.title = targetWindowName; } } } catch (ex) { // do nothing, just catch when the open fails. console.log("error: " + ex.message); } }, error: function(jqXhr, textStatus, errorThrown) { console.log('.... error :: ajax status = ' + textStatus + ' :: errorThrown = ' + errorThrown); console.log('....-- jqXhr.responseText :: \n' + jqXhr.responseText); } }) ).done( function() { console.log(".... report request has completed"); targetWindow.focus(); } );
Hi Team,
I would like to suggest that Progress/DevTools creates a SSO authentication service. I'll elaborate further with more details.
Thank you!
Inspect the Grid in the MVC demos.
The Grid renders the k-widget class.
The rendering must be consistent with jQuery and Core and the k-widget class should not be rendered. The issue is specifically in the MVC Grid. The Kendo UI for jQuery and the Core Grid no longer render this class.
This is the same as an existing feature request, which was marked as completed but it doesn't achieve what was originally requested.
Orgchart like the one in Telerik ASP.NET Ajax
The UI for ASP.NET MVC OrgChart component is missing functionality found in the UI for ASP.NET AJAX product.
The demos only show a small organisation dataset. With a large dataset (including up to 5 levels), I found the current MVC solution becomes unusable. For example, the vertical/horizontal scroll bar becomes tiny and navigation becomes difficult.
The extra functionality available in the AJAX works around issues, such as, zooming in/out and solves other basic requirements, such as Export to PDF.
Please make the AJAX Functionality and Application Scenarios available in the MVC product.
Test Environment:
OS Version: 22H2 OS Build 22621.1702
Edge Version: Edge(Chromium) Version 114.0.1823.37 (Official build) (64-bit)
Repro-Steps:
Test Environment:
OS Version: 22H2 OS Build 22621.1702
Edge Version: Edge(Chromium) Version 114.0.1823.37 (Official build) (64-bit)
Repro-Steps:
Hi !
So I work with Kendo UI for JQuery and Kendo UI for ASP.NET MVC and recently I had to use your combobox and found that the search was not accent insensitive and that there were no options to make it so. I think it would be a wonderful feature to have. My dataSource contains a lot of names that could potentially have accents and it would be really great to includes thoses names when I filter without accent.
Thank you !
My web page displays grids on multiple pages, and each grid has a pager with a page size control.
In recent updates the styling broke in all but one page.
In the case where I was creating the grid using Kendo UI for JQuery, it worked fine.
In the instances when I create it using MVC, there are styling errors. (See in the image how the number "10" is truncated.)
After much drilling into the HTML, I found the difference in how the Razor library creates the HTML elements, as opposed to how the JQuery creates the HTML elements.
JQuery generates the following element structure. Note that the k-pager-sizes element comes after the k-pager-numbers-wrap element
<div class="k-pager k-grid-pager k-pager-md"> <!-- The pager bar -->
<div class="k-pager-numbers-wrap">
<!-- ... -->
</div>
<span class="k-pager-sizes k-label">
<!-- The page-size picker goes here -->
</span>
</div>
In contrast, the Kendo Razor libraries generates the following element structure, where the k-pager-sizes element falls inside the k-pager-numbers-wrap element:
<div class="k-pager k-grid-pager k-pager-md"> <!-- The pager bar -->
<div class="k-pager-numbers-wrap">
<!-- ... -->
<span class="k-pager-sizes k-label">
<!-- The page-size picker goes here -->
</span>
</div>
</div>
This breaks the styling. (I am using the bootstrap kendo theme) There is styling rule that imposes a minimum width on all buttons under .k-pager-numbers-wrap. This makes the drop-down arrow too wide, which causes the page size number to truncate.
@each $size, $size-props in $kendo-pager-sizes {
$_padding-x: k-map-get($size-props, padding-x);
$_padding-y: k-map-get($size-props, padding-y);
$_item-group-spacing: k-map-get($size-props, item-group-spacing);
$_item-min-width: k-map-get($size-props, item-min-width);
$_pager-dropdown-width: k-map-get($size-props, pager-dropdown-width);
.k-pager-#{$size} {
padding-inline: $_padding-x;
padding-block: $_padding-y;
gap: $_item-group-spacing;
.k-pager-numbers-wrap {
.k-button {
min-width: $_item-min-width;
}
My current hack workaround is to add a more specific CSS rule.
@import "@progress/kendo-theme-bootstrap/dist/all.scss";
.k-pager-md .k-pager-numbers-wrap .k-dropdownlist .k-button {
min-width:inherit;
}
In a Selectable grid, when only one column is shown in the grid, and the model's Id field is specified, an error occurs on selection.
If you include more than one column (must be more than one visible) it works correctly.
If the model's Id is not specified, it works correctly even with only one column visible.
@(Html.Kendo().Grid<TelerikMvcApp1.Models.OrderViewModel>()
.Name("grid1")
.Columns(columns => {
columns.Bound(p => p.ShipName);
columns.Bound(p => p.ShipCity).Hidden(true);
})
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.Selectable(s => s.Mode(GridSelectionMode.Single))
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Orders_Read", "Grid"))
.Model(m => m.Id("OrderID"))
)
)
Dear team,
Recently I've updated the kendo UI.
currently I'm using the this version.
Here I wrote the code for testing.
// cshtml code
@(Html.Kendo().Grid<Alliant.Controllers.ProductViewModel>()
.Name("mixedSort")
.Columns(columns => {
columns.Bound(o => o.ProductName).Width(300);
columns.Bound(p => p.UnitPrice).Width(300);
columns.Bound(p => p.UnitsInStock).Width(300);
columns.Bound(p => p.Discontinued).Width(300);
columns.Bound(p => p.Group).Width(300);
})
.Pageable(pageable => pageable.ButtonCount(5))
.Sortable(sortable => sortable
.AllowUnsort(true)
.SortMode(GridSortMode.Mixed)
.ShowIndexes(true))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(5)
.Read(read => read.Action("Sorting_Orders_Read", "Testing"))
)
)
// Controller code
public ActionResult Sorting_Orders_Read([DataSourceRequest] DataSourceRequest request)
{
List<ProductViewModel> lstData = new List<ProductViewModel>()
{
new ProductViewModel(){Group="A",ProductName="A1",UnitPrice=10,Discontinued=1,UnitsInStock=50},
new ProductViewModel(){Group="A",ProductName="B1",UnitPrice=20,Discontinued=2,UnitsInStock=60},
new ProductViewModel(){Group="B",ProductName="C1",UnitPrice=30,Discontinued=3,UnitsInStock=70},
new ProductViewModel(){Group="C",ProductName="D1",UnitPrice=40,Discontinued=4,UnitsInStock=80},
new ProductViewModel(){Group="C",ProductName="E1",UnitPrice=50,Discontinued=5,UnitsInStock=90},
};
return Json(lstData.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
// Modelpublic class ProductViewModel
{
public string ProductName { get; set; }
public decimal UnitPrice { get; set; }
public int UnitsInStock { get; set; }
public decimal Discontinued { get; set; }
public string Group { get; set; }
}
Could you please help me to figure out the issue?
I also checked the jquery code.
// Jquery code render by kendo
Hi Team,
1. Date column filter value shown full date instead of dd/MM/yyyy format. If I change the format filter not working.
Sample screenshot:
2. When I click on grid or some other area on the page selected filter text value like('Last month', 'Last week', 'Today', 'Yesterday') from custom date filter dropdown
Grid:
@(Html.Kendo().Grid<InteractiveReports.Model.ViewModel.UserReportResult>()
.Name("userreport")
.HtmlAttributes(new { @class = "reportgrid" })
//.ToolBar(toolBar => toolBar.Template(
//"<a id='exportpdfdata' class='k-button k-button-icontext k-grid' href='#'><span class='k-icon k-i-pdf'></span>Export to PDF</a>" +
//"<a class='k-button k-button-icontext k-grid-excel' href='#'><span class='k-icon k-i-excel'></span>Export to Excel</a>" +
//"<a id='exportcsvdata' class='k-button k-button-icontext k-grid-csv' href='#'><span class='k-icon k-i-csv'></span>Export to CSV</a>"
//))
.Excel(excel => excel
.AllPages(true)
.FileName("User Report.xlsx")
.Filterable(true)
)
.Columns(columns =>
{
columns.Bound(c => c.Team).Title("Team Name").Filterable(ftb => ftb.Multi(true).Cell(cell => cell.ShowOperators(false).Template("TeamDropDownList")))
.Locked(true)
.ClientTemplate("<a class = 'link-button' title='Team Report' href='\\#' onclick=" + " onteamClick('#=escape(Team)#');>" + "#= Team != null && Team != '(Blanks)' ? Team : '' #" + "</a>")
.Width(200);
//columns.Bound(c => c.Team_type).Title("Team type").Filterable(ftb => ftb.Multi(true)).Width(200);
columns.Bound(c => c.Team_type).Title("Team type").Filterable(ftb => ftb.Multi(true).Cell(cell => cell.ShowOperators(false).Template("Team_typeDropDownList")))
.Width(200).ClientTemplate("#= (Team_type == '(Blanks)') ? '' : Team_type #");
columns.Bound(c => c.Username).Title("Username")
.Width(200).ClientTemplate("#= (Username == '(Blanks)') ? '' : Username #");
columns.Bound(c => c.Title).Title("Title").Width(200).ClientTemplate("#= (Title == '(Blanks)')? '' : Title #");
columns.Bound(c => c.First_name).Title("First Name").Width(200).ClientTemplate("#= (First_name == '(Blanks)') ? '' : First_name #");
columns.Bound(c => c.Last_name).Title("Last Name").Width(200).ClientTemplate("#= (Last_name == '(Blanks)') ? '' : Last_name #");
columns.Bound(c => c.Email_address).Title("Email Address")
.Width(200).ClientTemplate("#= (Email_address == '(Blanks)') ? '' : Email_address #");
columns.Bound(c => c.Company).Title("Company").Filterable(ftb => ftb.Multi(true).Cell(cell => cell.ShowOperators(false).Template("CompanyDropDownList")))
.Width(200).ClientTemplate("#= (Company == '(Blanks)') ? '' : Company #");
columns.Bound(c => c.User_status).Title("User Status").Filterable(ftb => ftb.Multi(true).Cell(cell => cell.ShowOperators(false).Template("User_statusDropDownList")))
.Width(200).ClientTemplate("#= (User_status == '(Blanks)') ? '' : User_status #");
columns.Bound(c => c.Total_time_logged_in).Title("Total Time Logged In").Width(200)
.ClientTemplate("#= (Total_time_logged_in == '(Blanks)') ? '' : Total_time_logged_in #");
columns.Bound(c => c.Last_login_date).Title("Last Login Date").Width(200)
//.ClientTemplate("#= Last_login_date != null ? Last_login_date : '' #")
.ClientTemplate("#= Last_login_date != null ? kendo.toString(Last_login_date, 'dd/MM/yyyy') : '' #")
.Format("{0:dd/MM/yyyy}")
//.Filterable(ftb => ftb.Cell(cell => cell.Template("datePickerFilter")));
.Filterable(f => f.Cell(c => c.ShowOperators(false).Template("dateFilterCustomization")));
columns.Bound(c => c.Last_login_time).Title("Last Login Time").Width(200)
.ClientTemplate("#= (Last_login_time == '(Blanks)') ? '' : Last_login_time #");
//.Filterable(f => f.Cell(c => c.ShowOperators(false).Template("timeFilterCustomization")));
columns.Bound(c => c.No_of_Index_Actions).Title("No. of Index Actions").Width(200)
.ClientTemplate("<a class = 'link-button' title='Index Report' href='\\#' onclick=" + " onidxActionClick('#=escape(UserId)#');>" + "#= No_of_Index_Actions != null ? No_of_Index_Actions : '' #" + "</a>")
.Filterable(ftb => ftb
.Cell(cell => cell
.Operator("eq")
.ShowOperators(false)
.Template("integerFilter_nodecimal")
)); })
.NoRecords(n => n.Template("NO DATA TO DISPLAY"))
.Events(events => events.Filter("onFiltering"))
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.ColumnMenu()
.Sortable()
.Scrollable()
.Filterable(ftb => ftb.Mode(GridFilterMode.Row))
.Events(events => events.Filter("onFilter"))
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
.PageSizes(new[] { 50, 100, 150 })
)
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Read(read => read.Action("GetUserReportData", "UserReport").Data("passParameter"))
.PageSize(50).Events(x => x.Error("onGridError"))
)
)
Customized Dropdown filter for date column:
var field = {};
var filter = true;
var dateformate = "DD/MM/YYYY";
const formatter = new Intl.DateTimeFormat(['ban', 'id'], { day: '2-digit', month: '2-digit', year: 'numeric' });
function dateFilterCustomization(args) {
var date = new Date();
var yesterday = new Date(date);
yesterday.setDate(date.getDate() - 1);
args.element.kendoComboBox({
dataSource: [
{ text: "Today", value: "1" },
{ text: "Yesterday", value: "2" },
{ text: "This Week", value: "3" },
{ text: "Last Week", value: "4" },
{ text: "Last Month", value: "5" },
{ text: "Since Live", value: "6" },
{ text: "Custom Date range", value: "7" },
],
placeholder: "Select",
dataTextField: "text",
dataValueField: "value",
dataTypeField: "",
valuePrimitive: true,
value: 7,
open: function (e) {
var grid = $('.reportgrid').data("kendoGrid");
var colname = e.sender.element[0].title;
field = getColName(grid.columns, colname);
if (grid.dataSource.filter() != undefined) {
var filters = checkForExistingDates(grid);
if (filters != undefined && filters.length > 0) {
var result = jQuery.grep(filters, function (item) { return item.operator == "gte" })
if (result != undefined && result.length > 0) {
$("#startDate").val(formatter.format(result[0].value));
}
else {
$("#startDate").val('');
}
result = jQuery.grep(filters, function (item) { return item.operator == "lte" })
if (result != undefined && result.length > 0) {
$("#endDate").val(formatter.format(result[0].value));
} else {
$("#endDate").val('');
}
}
else {
$("#startDate").val('');
$("#endDate").val('');
}
} else {
$("#startDate").val('');
$("#endDate").val('');
}
},
select: function (e) {
e.preventDefault();
var dataItem = e.dataItem;
var grid = $('.reportgrid').data("kendoGrid");
var colname = e.sender.element[0].title;
field = getColName(grid.columns, colname);
var vm = this;
var text = dataItem.text;
flag = parseInt(dataItem.value);
if (flag == 1) {
filterSingleDate(date);
} else if (flag == 2) {
filterSingleDate(yesterday);
} else if (flag == 3) {
getThisWeekData();
} else if (flag == 4) {
getPastWeekData();
} else if (flag == 5) {
getPastMonthData();
} else if (flag == 6) {
removeFilter(grid);
}
else if (flag == 7) {
$(".daterangemodel").modal('toggle');
}
vm.text(text);
}
});
}
function startOfLastWeek() {
var today = moment();
var daystoLastMonday = 0 - (1 - today.isoWeekday()) + 7;
var lastMonday = today.subtract('days', daystoLastMonday);
return lastMonday;
}
function EndOfLastWeek() {
var lastMonday = startOfLastWeek();
var lastSunday = lastMonday.add('days', 6);
return lastSunday;
}
function getPastWeekData() {
var startDate = startOfLastWeek();
var endDate = EndOfLastWeek();
filterData(startDate, endDate, field);
}
function getThisWeekData() {
var date = new Date();
var startDate = startOfThisWeek(date);
var endDate = endOfThisWeek(date);
filterData(startDate, endDate, field);
}
Script:
function onFilter(e) {
if (e.filter && e.filter.filters[0].field == "Last_login_date" || e.filter && e.filter.filters[0].field == "Creation_date" || e.filter && e.filter.filters[0].field == "Invitation_date" || e.filter && e.filter.filters[0].field == "Registration_date") {
Model:
public class UserReportResult
{
public string Team { get; set; }
public string Team_type { get; set; }
public string Username { get; set; }
public string Title { get; set; }
public string First_name { get; set; }
public string Last_name { get; set; }
public DateTime ? Last_login_date { get; set; }
}
Can any admin tell me what is wrong??