Kendo Method ToDataSourceResult gives timeout exception for large number of records - kendo-grid

I am using Kendo Grid as below:
Html.Kendo().Grid<MyViewModel>()
.Name("grid")
.Columns(c => c.AutoGenerate(false))
.Filterable(f =>
{
//coding for filteration
})
.Selectable(selectable => selectable.Mode(GridSelectionMode.Single))
.Reorderable(r => r.Columns(true))
.Pageable(pager => pager
.Refresh(true)
//coding for pages
)
.Sortable().Selectable(selectable => selectable.Mode(GridSelectionMode.Multiple))
.Scrollable(s => s.Height(450))
.Filterable()
.Resizable(r => r.Columns(true))
.DataSource(dataSource => dataSource.Ajax()
.Events(ev => ev.RequestEnd("onRequestEnd"))
.Sort(sort => { sort.Add(model => model.Date).Descending(); })
.Filter(f => f.Add(model => model.SerialNo).IsEqualTo((this.Session["Id"] as MyModel).SerialNo)) // Applying Custom Filter
.PageSize(10)
.ServerOperation(true)
.Read(read => read.Action("Read", "Controller").Data("Grid_Index_additionalData")))
.Events(events => events.DataBound("onDataBound"))
.Render();
Code in Controller :
[OutputCache(Duration = 0, VaryByParam = "None")]
public ActionResult Read([DataSourceRequest]DataSourceRequest request, string searchBox)
{
IQueryable<MyViewModel> filteredResult;
var collection1 = manager.Model1SelectAll();
var collection2 = manager.Model2SelectAll();
filteredResult = from c1 in collection1
join c2 in collection2
on c1.SerialNo equals c2.SerialNo
select new MyViewModel
{
Prop1 = c1.Prop1,
Prop2 = c1.Prop2,
Prop3 = c1.Prop3,
Prop4 = c1.Prop4,
SerialNumber = c1.SerialNo,
Prop5 = c2.Prop5,
Prop6 = c2.Prop6
};
var result = filteredResult.ToDataSourceResult(request);
// filteredResult is IQueryable of around 3 million records
// filtering these on basis of request.Sorts and request.Filter will give 100 records
// But I receive TimeOut exception here
try
{
var serializer = new JavaScriptSerializer { MaxJsonLength = int.MaxValue };
var jsonResult = new ContentResult
{
Content = serializer.Serialize(result),
ContentType = "application/json"
};
return jsonResult;
}
catch (Exception ex)
{
ExceptionService.LogException(ex);
}
}
My filteredResult contains 3 million records which gives TimeOut Exception while calling ToDataSourceResult().
Also if I try to use filteredResult.ToList() => that gives me MemoryException.
I am unable to remove Timeout exception. Kendo says that if we pass IQueryable to ToDataSourceResult, it will handle all filtering, But in my case it gives exception.
I have tried creating my own alternative of ToDataSourceResult() by handling all request.Sorts and Filters and passign just pagesize records using
this.ObjectSet.Where(whereCondition).OrderBy("it." + sortBy).Skip(pageSize * (pageNumber - 1)).Take(pageSize);
But this way I am unable to handle all the cases of filter and make this method generic for all the grids in my project.

Related

Kendo UI Grid SignarlR datasource not firing update event

I'm using asp.net core razor pages with a Kendo Grid that is datasourced using SignalR. It gets the initial read ok, but the update does not fire. I've looked at the Kendo Demo, and other stackover flow pages, but nothing seems to work.
I know the API works fine in sending the update because I see the call when debugging through Chrome that the websocket received an update commmand with the new data in json format. But the Grid doesn't update, or fire any update commands. It's as if it never received it, or doesn't know that it received it.
Index.cshmtl
<script src="~/signalr/signalr.js"></script>
<script>
var url = https://demosite.com/hub/controller;
var hub = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Information)
.withUrl(url,
{
transport: signalR.HttpTransportType.WebSockets | signalR.HttpTransportType.LongPolling
})
.build();
var hubStart = hub.start();
</script>
#(Html.Kendo().Grid<myModel>
()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.Name);
columns.Bound(c => c.Date);
})
.HtmlAttributes(new { style = "width: 98%;" })
.DataSource(dataSource => dataSource
.SignalR()
.AutoSync(true)
.ServerFiltering(true)
.ServerSorting(true)
.PageSize(10)
.Transport(tr => tr
.Promise("hubStart")
.Hub("hub")
.Client(c => c
.Read("read") //Read works, initial data loads
.Create("create")
.Update("update")
.Destroy("destroy")
)
.Server(s => s
.Read("read")
.Create("create")
.Update("update")
.Destroy("destroy")
)
)
.Schema(schema => schema
.Data("Data")
.Total("Total")
.Aggregates("Aggregates")
.Model(model =>
{
model.Id(p => p.ID);
model.Field(p=> p.Name);
model.Field(p => p.Date);
}
)
)
)
.Group(g => g.Add(x => x.Name))
)
.Events(x=>
{
x.DataBound("collapseAllGroups");
}
)
.Groupable(true)
.Sortable()
.Filterable()
.Pageable(pager => pager.AlwaysVisible(true).PageSizes(new int[] { 10, 20, 50, 100 }))
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.Selectable()
)
Api
[HttpGet]
public async Task<myModel> GetTest()
{
myModel mod= new myModel();
mod.Name = "New Name";
mod.Date = DateTime.UTCNow.ToString();
//Send update command to connected SignalR Clients
await _hub.Clients.All.SendAsync("update", mod);
return mod;
}
Any help would be appreciated.
Ok I got this to work. Turns out that since the Grid is originally expecting a DataSourceResult I had to convert myModel to a DataSourceResult type before doing the update. Example below should be considered Pseudocode as I’m typing this on my phone.
await _hub.Clients.All.SendAsync("update", new DataSourceResult(mod));

No data of first load

I'm new to NgRx, and trying to retrieve and cache paginated table data using Effects and http request.
But on any first time page load (if page isn't cached already) I got empty page, even though if I do console.log of state object, I see data inside?
When I go on previous page, data is there, so I'm guessing something in async world I'm doing wrong, but can't figure out what :/
here is my initialization in
component.ts
ngAfterViewInit() {
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page)
.pipe(
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
this.store.dispatch(new ListLoad(this.getQueryParams()));
return this.store.pipe(select('list'));
}),
map((state: State) => {
this.isLoadingResults = false;
this.resultsLength = state.totalRecords;
return this.cacheKey in state.data ? state.data[this.cacheKey] : [];
}),
catchError((err) => {
this.isLoadingResults = false;
this.resultsLength = 0;
return observableOf([]);
})
)
.subscribe((data: any[]) => {
return this.data = data
});
}
and here is my effect definition
effects.ts
#Effect()
loadData = this.actions$.pipe(
ofType(actions.actionTypes.ListLoad),
mergeMap((action: actions.actionTypes.ListLoadSuccess) => this.service.getAll(action.payload).pipe(
map(
response => {
let apiResponse = new ApiResponse(response);
let cacheKey = JSON.stringify(action.payload);
return apiResponse.isSuccess ?
new actions.ListLoadSuccess({ key: cacheKey, data: apiResponse.data }) :
new actions.ListLoadFailed(`code: ${apiResponse.status.error_code}; message: ${apiResponse.status.error_message}`);
}
),
catchError(err => observableOf(new actions.ListLoadFailed(err)))
))
)
In addition to this, I would like to cancel http request, if page containing the data is present in NgRx store
I was able to resolve it. Issue was that I was updating property of store which is object, by adding new property to it. Store does not emit event that fragment is updated, so Select subscription is not triggered. I've introduced another boolean param for loading state, which I listen for changes, and if loading is false (page is loaded), I select desired fragment.
I've also added extra code for page caching
component.ts
ngOnInit() {
this.isLoadingResults$ = this.store.pipe(
select(state => state.stateFragment.isListLoading),
takeWhile(() => this.componentActive) //unsubscribe
);
this.store.dispatch(new ListLoad());
this.isLoadingResults$.pipe(
filter((isLoading:boolean) => !isLoading),
switchMap(() => this.store.pipe(
select(state => state.stateFragment),
takeWhile(() => this.componentActive) //unsubscribe
)),
map(...)
).subscribe(...);
//Other stuff here
}
effects.ts
#Effect()
load$ = this.actions$.pipe(
ofType(actions.actionTypes.ListLoad),
withLatestFrom(this.store.pipe(select(state.stateFragment))),
filter(([action, store]) => {
let isPageCached: boolean = action.payload in store.stateFragment;
if (isPageCached) {
this.store.dispatch(new actions.ListLoaded()); //for sake of changing loading state
}
return !isPageCached;
}),
switchMap(([action, store]) => {
return this.service.getAll(action.payload).pipe(
map(
response => {
let apiResponse = new ApiResponse(response);
return apiResponse.isSuccess ?
new actions.ListLoadSuccess({ key: action.payload, data: apiResponse.getData(), totalRecords: apiResponse.getTotalCount() }) :
new actions.ListLoadFailed(`code: ${apiResponse.status.error_code}; message: ${apiResponse.status.error_message}`);
}
),
catchError(err => observableOf(new actions.ListLoadFailed(err)))
);
}
), share()
)
reducer.ts
export function reducer(state = initialState, action: Actions) {
switch (action.type) {
case actionTypes.ListLoad:
return {
...state,
isListLoading: true
};
case actionTypes.ListLoaded:
return {
...state,
isListLoading: false
};
case actionTypes.ListLoadSuccess:
state.listData[action.payload.key] = action.payload.data;
return {
...state,
isListLoading: false,
listData: state.listData,
listTotal: action.payload.totalRecords
};
case actionTypes.ListLoadFailed:
return {
...state,
isListLoading: false,
error: action.payload
};
case actionTypes.ListClear:
return {
...state,
listData: {},
listTotal: 0
};;
default:
return state;
}
}

Cannot read property length of undefined error happens only in server

I am using MVC and Kendo Grid. I am facing an issue where we have common functions for all our master tables and stores the result set to a cache based on dealersystemId.
There are different dealersystemId, so data will be stored in the cache for each of dealersystemId.
So whenever a call required for a master table, it always uses cache rather than going to call master tables, if there is no data in the cache for a particular master table only then it hit the database, otherwise reads from the cache.
We have a screen it shows all data from the cache, and the user will be able to delete stored cache for each dealersystemid. So here when a user clicks on 'clearcache' button for a dealersystemId, a Jquery ajax will happen and it deletes data from the cache for a dealersystemid, and remaining data in the cache will be shown in the Kendo grid.
Function which clears cache data code as mentioned below,
public List<SystemPreferenceModel> ClearAllSysPreference(string dealerSystemID,bool selfClear = true)
{
try
{
List<SystemPreferenceModel> systemPreferenceModel = null;
List<mtSystemPreference> appSystemPrefModel = null;
appSystemPrefModel = (List<mtSystemPreference>)CachingProvider.Instance.GetItem("GetAllSysPreference2");
if (appSystemPrefModel != null)
{
systemPreferenceModel = new List<SystemPreferenceModel>();
IGenericDataRepository<mtSystemPreference> appSysPrefRepository = new GenericDataRepository<mtSystemPreference>(UserModelSession);
appSystemPrefModel.RemoveAll(x => x.dealerSystemId == Convert.ToInt64(dealerSystemID));
systemPreferenceModel = GetSystemPreferenceData(appSystemPrefModel);
CachingProvider.Instance.AddItem("GetAllSysPreference2", appSystemPrefModel, string.Empty);
}
var appSettings = ConfigurationManager.AppSettings;
string server1 = appSettings["Server1"];
string server2 = appSettings["Server2"];
if (selfClear == true && !server1.Contains("localhost"))
{
string Server1IPAddress = server1.Split(':')[1].Substring(2);
if (UserModelSession.ServerIPAddress != Server1IPAddress)
{
server2 = server1;
}
NetTcpBinding tcpb;
string PropagationEndPoint = "";
PropagationEndPoint = server2 + "/CommonComponent";
tcpb = new NetTcpBinding();
tcpb.Security.Mode = SecurityMode.None;
EndpointAddress ep = null;
ep = new EndpointAddress(PropagationEndPoint);
using (ChannelFactory<ICommonComponent> factory = new ChannelFactory<ICommonComponent>(tcpb))
{
ICommonComponent proxy = factory.CreateChannel(ep);
using (OperationContextScope scope = new OperationContextScope((IContextChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("usermodel", "utp_ns", ""));
proxy.ClearAllSysPreference(dealerSystemID, false);
}
}
}
return systemPreferenceModel;
}
catch (Exception ex)
{
bool rethrow = BusinessLogicExceptionHandler.HandleExcetion(ref ex);
if (rethrow)
{
throw ex;
}
return null;
}
}
It works fine in local. View as follows
<div id="dvSysPref">
<div style="padding-bottom:0px; padding-top:5px;">
#(Html.Kendo().Grid(Model.mtSystemPreferenceViewModel)
.Name("SystemPreferenceGrid")
.Selectable()
.Columns(columns =>
{
columns.Bound(model => model.entityType).Width("50px").Title("EntityType");
columns.Bound(model => model.entityId).Width("150px").Title("EntityID");
columns.Bound(model => model.dealerSystemId).Width("150px").Title("Dealer SystemID");
columns.Bound(model => model.name).Width("150px").Title("name");
columns.Bound(model => model.valInt).Width("50px").Title("ValInt");
columns.Bound(model => model.valString).Width("150px").Title("ValString");
columns.Bound(model => model.createdDate).Width("150px").ClientTemplate("#= kendo.toString(createdDate, \"MM/dd/yy hh:mm tt\") #").Title("createdDate");
columns.Bound(model => model.lastUpdatedDate).Width("150px").ClientTemplate("#= kendo.toString(lastUpdatedDate, \"MM/dd/yy hh:mm tt\") #").Title("LastUpdatedDate");
columns.Bound(model => model.isActive).Width("150px").Title("IsActive");
columns.Bound(model => model.valBin).Width("100px").Title("ValBin");
})
.HtmlAttributes(new { style = "font-size: 14px; font-family: 'Segoe UI'; min-height: 100px; table-layout: fixed;" })
.Pageable(pg =>
pg.Refresh(true)
.PageSizes(new int[] { 10, 30, 50, 100, 200 })
.Enabled(true)
.PreviousNext(true)
.Numeric(false)
.Input(true)
.Messages(m => m.Page("Page ")
.Of(" of {0}")
)
)
.Navigatable()
.Filterable()
.Scrollable(scr => scr.Height(400))
.Sortable(sort => sort.SortMode(GridSortMode.SingleColumn))
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
.NoRecords("No Records Found")
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.ServerOperation(false)
.Model(model =>
{
model.Id(p => p.mtSystemPreferenceId);
model.Field(p => p.entityType);
model.Field(p => p.entityId);
model.Field(p => p.name);
model.Field(p => p.valInt);
model.Field(p => p.valString);
model.Field(p => p.createdDate);
model.Field(p => p.createdBy);
model.Field(p => p.lastUpdatedDate);
model.Field(p => p.lastUpdatedBy);
model.Field(p => p.dealerSystemId);
model.Field(p => p.isActive);
model.Field(p => p.valBin);
}
)
.Read(read => read.Action("ReadSystemPreferenceListGrid", "ClearCache"))
)
)
</div>
<div style="padding-bottom:0px; padding-top:5px;">
#(Html.Kendo().DropDownList()
.Name("DealerSystemSysPreferenceList")
.BindTo(Model.SystemPreferenceDealerSystemViewModelList)
.DataTextField("DealerSystemID")
.DataValueField("ID")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("LoadSystemSysPreferenceListDropdown", "ClearCache");
})
.ServerFiltering(true);
})
.Events(e =>
{
e.DataBound("onSystemPreferenceDataBound");
})
.OptionLabel("Select Dealer System ID")
.HtmlAttributes(new { style = "width: 30%" })
)
<input type="button" id="btnSysPreferenceClearCache" class="btn btn-default btn-primary" title="Search" value="Clear Cache" />
<div>
<span id="dvSystemPreferenceListvalidMesg" class="k-widget k-tooltip k-tooltip-validation k-invalid-msg field-validation-error" role="alert" style="display:none;text-align:left;position:absolute;margin:0px!important;padding:1px!important;bottom: 400px;"><span class="k-icon k-warning"> </span> Please select a dealer system ID</span>
</div>
</div>
JQuery ajax code,
function onSystemPreferenceDataBound(e) {
$("#btnSysPreferenceClearCache").click(function () {
var dealerSystemID = $("#DealerSystemSysPreferenceList").data("kendoDropDownList").text();
if (dealerSystemID != "Select Dealer System ID") {
$.ajax({
type: "GET",
url: '/ClearCache/ClearSystemPreferenceListCache',
data: { dealerSystemID: dealerSystemID },
pageSize: 20,
cache: false,
pageable: true,
success: function (src) {
alert('Systempreference Cache has been cleared for dealerSystemId '+dealerSystemID);
var dealerDropdown = [];
var dropdownList = [];
if (src.Data.length > 0) {
for (var i = 0; i < src.Data.length; i++) {
dropdownList.push({ text: src.Data[i].dealerSystemId, value: i });
}
//Removes duplicates from dropdown
dealerDropdown = dropdownList.reduce(function (item, e1) {
var matches = item.filter(function (e2)
{ return e1.text == e2.text });
if (matches.length == 0) {
item.push(e1);
}
return item;
}, []);
dealerDropdown.unshift({ text: "Select Dealer System ID", value: "0" });
}
else {
dealerDropdown = [
{ text: "Select Dealer System ID", value: "0" },
];
}
var dataSource = new kendo.data.DataSource({
data: src,
pageSize: 20,
schema: {
type: "json",
data: "Data",
total: "Total",
model: {
fields: {
mtSystemPreferenceId: { type: "number" },
entityType: { type: "number" },
name: { type: "string" },
dealerSystemId: { type: "number" },
valInt: { type: "number" },
valString: { type: "string" },
createdDate: { type: "date" },
createdBy: { type: "number" },
lastUpdatedDate: { type: "date" },
lastUpdatedBy: { type: "number" },
isActive: { type: "bool" },
}
}
}
});
$('#SystemPreferenceGrid').data('kendoGrid').setDataSource(dataSource);
$("#DealerSystemSysPreferenceList").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
dataSource: dealerDropdown
});
}
});
}
else {
alert('Please select a DealerSystemID');
}
});
}
my Controller code as follows,
public ActionResult ClearUsersListCache(string dealerSystemID)
{
SupportViewModel supportVM = new SupportViewModel();
UsersViewModel usersListModel = new UsersViewModel();
supportVM.userViewModelList = new List<UsersViewModel>();
List<UserModel> UserListInfoModel = new List<UserModel>();
List<DealerSystemViewModel> dealerSystemViewmodel = new List<DealerSystemViewModel>();
supportVM.UsersDealerSystemViewModelList = new List<DealerSystemViewModel>();
DTNAUserModel dtnaUserModel = (DTNAUserModel)System.Web.HttpContext.Current.Session["DTNAConnectUser"];
DTNAUserModel systemUserLoginModel = new DTNAUserModel();
try
{
using (BusinessLayerServiceFactory<ICommonComponent> commonComponentServiceFactory = new BusinessLayerServiceFactory<ICommonComponent>())
{
ICommonComponent commonComponent = commonComponentServiceFactory.Instantiate();
using (OperationContextScope ocs = new OperationContextScope((IContextChannel)commonComponent))
{
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader(commonComponentServiceFactory.UserModelName, commonComponentServiceFactory.UserModelNameSpace, commonComponentServiceFactory.SerializedUserModel));
UserListInfoModel = commonComponent.ClearAllUsers(dealerSystemID);
}
}
if (UserListInfoModel != null)
{
foreach (var user in UserListInfoModel)
{
UsersViewModel userViewModel = new UsersViewModel();
{
{
userViewModel.Gid = user.Gid;
userViewModel.mtUserId = user.mtUserId;
userViewModel.BranchId = user.BranchId;
userViewModel.DeptId = user.DeptId;
userViewModel.UserId = user.UserId;
userViewModel.DmsUserId = user.DmsUserId;
userViewModel.DealerSystemId = user.DealerSystemId;
userViewModel.Description = user.Description;
userViewModel.Email = user.Email;
userViewModel.Role = user.Role;
userViewModel.isActive = user.isActive;
userViewModel.Password = user.Password;
userViewModel.RecActive = user.RecActive;
userViewModel.Facility = user.Facility;
}
supportVM.userViewModelList.Add(userViewModel);
}
}
for (int i = 0; i < UserListInfoModel.Count; i++)
{
supportVM.UsersDealerSystemViewModelList.Add(new DealerSystemViewModel { DealerSystemID = UserListInfoModel[i].DealerSystemId.ToString(), ID = Convert.ToInt64(i + 1) });
}
//This removes duplicates
supportVM.UsersDealerSystemViewModelList = supportVM.UsersDealerSystemViewModelList.GroupBy(i => i.DealerSystemID).Select(g => g.First()).ToList();
}
var result = new DataSourceResult()
{
Data = supportVM.userViewModelList.OrderByDescending(x => x.mtUserId), // Process data (paging and sorting applied)
Total = supportVM.userViewModelList.Count // Total number of records
};
var jsonResult = Json(result, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
catch (Exception ex)
{
bool rethrow = UserInterfaceExceptionHandler.HandleException(ref ex);
if (rethrow)
{
throw ex;
}
return null;
}
}
However, when it got deployed we are able to see one javascript error 'Can not read property length of undefined'. This error happens only in the server not in local. When I debugged I could see that in Jquery success function controller returns view instead data which causes this error. Hence in the data return in success function is undefined, hence in 'src.Data.length' length property comes as undefined.
SystemPreferenceGrid
Please note I have attached a screenshot for the same error happens for one more grid we have.
But we could not reproduce this issue in local. So could anyone help me in fixing this issue?

How to pass object as parameter to kendo grid read method

I have kendo grid as follow.
#(Html.Kendo().Grid<ManualInputDetail>()
.Name("gManualInputDetail")
.Columns(columns =>
{
columns.Bound(c => c.Id).Hidden(true);
columns.Bound(c => c.Month).Title("Month");
columns.Bound(c => c.Value).Title("Value");
})
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Pageable()
.Navigatable()
.Selectable(selectable =>
{
selectable.Mode(GridSelectionMode.Single);
selectable.Type(GridSelectionType.Row);
})
.Sortable(sortable =>
{
sortable.SortMode(GridSortMode.MultipleColumn);
})
.DataSource(dataSource => dataSource
.WebApi()
.Model(model => model.Id(p => p.Id))
.PageSize(12)
.Read(read => read.Url(Url.HttpRouteUrl("ActionApi", new { controller = "ManualInputDetails", action = "GetManualInputDetails" })).Data("getFilterData"))
)
.Pageable(p => p.Refresh(true))
)
using getFilterData function I want to pass object parameter to read method. getFilterData function as follow
function getFilterData() {
var header= {
SectorId: 1,
BrandId: 2,
LocationId: 1,
DataElementId:2
}
return {
header: header
};
}
GetManualInputDataElements method as follow
[ActionName("GetManualInputDetails")]
public DataSourceResult GetManualInputDetails([System.Web.Http.ModelBinding.ModelBinder(typeof(WebApiDataSourceRequestModelBinder))] DataSourceRequest request,ManualInputHeader header)
{
var model = new DataElementMgt().GetAll(header).Select(x => new DataElement()
{
Id = x.Id,
DataElementTypeId = x.DataElementTypeId,
Name = x.Name,
Descriptionn = x.Descriptionn
}).ToList().ToDataSourceResult(request);
return model;
}
In here header value always gives as null. What is the reason for that. Is any thing wrong? Please help..
change the getFilterData method to this
function getFilterData() {
var _header= {
SectorId: 1,
BrandId: 2,
LocationId: 1,
DataElementId:2
}
return {
header: _header
};
}
and it should work. dont use the same name for what you return and declare.

Error event handling causes Read to not be called

Below is my PartialView for a Kendo Grid. As of now, my Parts_Read action is NOT called. But, if I comment out
.Events(events => events.Error("error_handler"))
Then everything works fine. Any ideas of why this is happening?
#using Kendo.Mvc.UI;
#using eRPortalDashboard.Models
#model PMPartsViewModel
#{
int PMNumber = Model.PMNumber;
string uniqueName = Model.PartsGrid.ID;//Regex.Replace(Guid.NewGuid().ToString(), "[^A-Za-z]+", "");
bool enableToolbar = Model.PartsGrid.EnableToolbar;
bool enablePageable = Model.PartsGrid.Pageable;
bool enableSortable = Model.PartsGrid.Sortable;
bool enableColumnMenu = Model.PartsGrid.EnableColumnMenu;
bool enableGroupable = Model.PartsGrid.Groupable;
bool enableColumnResizing = Model.PartsGrid.AllowColumnResizing;
bool enableScrolling = Model.PartsGrid.Scrollable;
bool enableSelection = Model.PartsGrid.Selectable;
}
#(Html.Kendo().Grid<PartViewModel>()
.Name(uniqueName)
.Columns(columns =>
{
columns.Bound(c => c.ItemNumber);
columns.Bound(c => c.Description);
})
.ToolBar(toolBar =>
{
toolBar.Custom().Text("Test Button").Url("#").HtmlAttributes(new { id = "testButton" });
})
.Pageable(pager => pager
.Input(false) //Using pageable.numeric and pageable.input at the same time is not recommended.
.Numeric(true)
.Info(true)
.PreviousNext(true)
.Refresh(true)
.PageSizes(new object[] { 5, 10, 20, 50, "all" })
.Enabled(enablePageable)
)
.Selectable(s => s.Mode(mode: GridSelectionMode.Multiple).Enabled(enableSelection))
.AllowCopy(enableSelection) //selectable needs to be enabled and set to multiple
.Sortable(s => s.SortMode(GridSortMode.MultipleColumn).Enabled(enableSortable))
.ColumnMenu(c => c.Enabled(enableColumnMenu))
.Groupable(g => g.Enabled(enableGroupable))
.Scrollable(s => s.Height("auto").Enabled(enableScrolling))
.Resizable(resize => resize.Columns(enableColumnResizing))
//.Events(events => events.DataBound(uniqueName + "_updateGrid").Change(uniqueName + "_updateGrid"))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(true)
.Events(events => events.Error("error_handler"))
.Read("Parts_Read", "PM", new { PMNumber = PMNumber })
)
)
<script type="text/javascript">
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
alert(message);
}
}
The main crux of my issue was the fact that error_handler was declared after my MVC code, thereby making it unable to bind to the method.
Apparently, with Kendo (maybe others), when using Partial Views, the javascript function must be declared BEFORE it is used in Razor syntax for that view.
see also: telerik forum post