Try to change the columns list dynamically via a query ...
When I construct the TreeList, I call for columns :
$("#treelist").kendoTreeList({
columns: AnalyseCenterSKUService.getKPIColumnList($scope)
If I return a simple array with the fields, it's working ..
If I call a $http.get (inside my getKPIColumnList(..) function) which add some columns to the existing array of columns, the TreeList is not constructed correctly.
Any suggestion will be really appreciated ! :)
EDIT 22-10-2019 09:00
Treelist init
$("#treelist").kendoTreeList({
columns: AnalyseCenterSKUService.getKPIColumnList($scope),
scrollable: true,
columnMenu : {
columns : true
},
height: "100%",
dataBound: function (e) {
ExpandAll();
},
dataSource: {
schema: {
model: {
id: "id",
parentId: "parentId",
fields: {
id: { type: "number" },
parentId: { type: "number", nullable: true },
fields: {
id: { type: "number" },
parentId: { type: "number", nullable: false }
}
}
}
},
transport: {
read: {
url: "/api/AnalyseCenter/GetWorkOrderTree/0",
dataType: "json"
}
}
}
The getKPIColumnList return an static array + some push with dynamic columns (from DB)
angular.module('AnalyseCenterDirectives')
.service ('AnalyseCenterSKUService', function ($http) {
var toReturn = [ {field: "Name", title: "HiƩrachie SKU", width: "30%" }, ..., ..., .... ];
I try in this function to push DB result
return $http.get("/api/AnalyseCenter/GetWorkOrderHistorianAdditonalColumns?equipmentName=" + equipmentName)
.then(function (result) {
var data = result.data;
if (data && data !== 'undefined') {
var fromDB = data;
angular.forEach(fromDB, function (tag) {
var tagName = tag.replace(".","_");
toReturn.push({
field: tagName, title: tag, width: '10%',
attributes: { style: "text-align:right;"} })
})
The stored procedure GetWorkOrderHistorianAdditonalColumns returns a list of string (future column)
That is because ajax is async, that means your tree list is being initialized before the request finishes. A classic question for JavaScript newcomers. I suggest you take a while to read about ajax, like How does AJAX works for instance.
Back to your problem. You need to create your tree list inside the success callback(I can't give you a more complete solution since I don't know what you're doing inside your function or which framework you're using to open that ajax request) with the result data, which is probably your columns. Then it would work as if you're initializing it with arrays.
I have a table that shows a pop-up when the first cell is clicked like this:
$('#tblAllUsers tbody').on('click', 'td', function () {
var visIdx = $(this).index();
if (visIdx != 0) {
return false;
}
var par = this.parentNode.parentNode.id;
var oTable = $("#tblAllUsers").dataTable();
var rowIndex = $(this).closest('tr').index();
var aPos = oTable.fnGetPosition(this);
var aData = oTable.fnGetData(aPos[0]);
var name = aData[1];
if (name != '') {
GetUser(name, rowIndex, "#tblAllUsers");
}
else {
ErrorDialog("#MessageDialog", "#lblError", "The User ID is blank in that row.", "No User ID");
return false;
}
});
The pop-up allows the user to modify fields and save it, close the dialog and then return to the grid. If the dialog is canceled, data not saved, the scroll is maintained. But if the data is saved, and I am not reloading the table, the table moves to the top. The AJAX update function is within the pop-up:
$.ajax({
type: 'POST',
data: $("#formUserModification").serializeArray(),
url: '#Url.Action("UpdateUser")',
success: function (data) {
if (data.Errors === 'ERROR') {
ErrorDialog("#MessageDialog", "#lblError", "There was an error encountered in modifying the user, please try again later.", "Error");
}
else {
updateTable(data);
}
$("#divDetails").dialog('close');
},
beforeSend: function () {
$("#divOverlay").show();
},
complete: function () {
$("#divOverlay").hide();
}
});
The update function simply loads the row:
function updateTable(data) {
var tab = $("#tblAllUsers").dataTable();
tab.fnUpdate(data.LastName + ', ' + data.FirstName, data.RowIndex, 0);
tab.fnUpdate(data.ID, data.RowIndex, 2);
tab.fnUpdate(data.LocationText, data.RowIndex, 3);
tab.fnUpdate(data.SiteText, data.RowIndex, 4);
}
Is there a way with this setup to keep the scroll position?
I accomplished my goal by doing this:
Define a variable:
var scrollToPos;
In the dialog definition set the value when it is opened and place the scroll bar when it is closed:
$("#divAllUsersDetail").dialog({
autoOpen: false,
width: '90%',
resizable: false,
draggable: false,
title: 'Details',
position: { my: 'top', at: 'top+100' },
modal: true,
closeOnEscape: false,
open: function() {
scrollToPos = $("#divAllUsers").find(".dataTables_scrollBody").scrollTop();
},
close: function () {
$("#divAllUsers").find(".dataTables_scrollBody").scrollTop(scrollToPos);
},
show: {
effect: 'drop', direction: 'up'
},
hide: {
effect: 'fade', duration: 200
},
buttons: {
"Cancel": function () {
$(this).dialog("close");
}
}
}).prev("ui-dialog-titlebar").css("cursor", "default");
This works famously.
Is it possible in fullcalendar-scheduler to pass start and end date of the view to the resources? eventSources are provided with these two parameters automatically, but resources not. I tried with
resources: {
url: '<?= $resourcesRoute ?>,
type: 'POST',
data: {
start: $('#calendarDaysoff').fullCalendar('getView').start,
}
},
eventSources: [
{
url: '<?= $eventsRoute ?>',
type: 'POST',
data: {
bla: 'bla'
},
error: function () {
alert('There was an error while fetching events!');
}
}
],
but this does not works.
I used this solution:
resources: function(callback){
setTimeout(function(){
var view = $('#calendar').fullCalendar('getView');
$.ajax({
url: 'feed.php',
dataType: 'json',
cache: false,
data: {
start: view.start.format(),
end: view.end.format(),
timezone: view.options.timezone
}
}).then(function(resources){callback(resources)});
},0);
},
This will add start and end parameters like when fetching events. You can add
$feed_start = $_GET['start']; to feed.php
and use the variable '$feed_start' in mysql select.
I got the input from https://github.com/fullcalendar/fullcalendar-scheduler/issues/246?_pjax=%23js-repo-pjax-container
V1.5.1 introduces a solution:
https://fullcalendar.io/docs/resource_data/refetchResourcesOnNavigate/
Since v1.5.1, if refetchResourcesOnNavigate is set to true a resources function will receive start, end, and timezone parameters
I am implementing server side paging & sorting for jqGrid in MVC 4. I am passing view model object as postData to jqGrid url action method. have a look at grid definition.
var isGridDefined = false;
$(document).ready(function () {
function DefineGrid(Year, Month) {
var mygrid = $("#RptUpload");
mygrid.jqGrid({
loadonce: false,
async: false,
datatype: 'json',
postData: { bReload: true, Year: Year, Month: Month },
url: '#Url.Action("DMEUploadDetailsList", "Reports")',
jsonReader: { repeatitems: false, root: "DataRows" },
colNames: ['#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_OrderID',
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_CompanyName',
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientID',
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientName',
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_DOB",
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Insurance',
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_UploadDate"
],
colModel: [
{ name: 'ReadingID', index: 'ReadingID', width: 55, fixed: true, sorttype: 'integer', align: 'center' },
{
name: 'CompanyName', index: 'CompanyName', align: 'center', width: 200,
cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal!important;' },
},
{ name: 'PatientID', index: 'PatientID', width: 55, fixed: true, sorttype: 'integer', align: 'center' },
{
name: 'PatientName', index: 'PatientName', align: 'center', width: 200,
cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal!important;' },
},
{
name: 'DOB', index: 'DOB', width: 80, fixed: true, sorttype: 'date', formatter: 'date', formatoptions: { srcformat: 'm/d/Y', newformat: 'm/d/Y' },
align: 'center'
},
{ name: 'InsuranceType', index: 'InsuranceType', align: 'center', width: 150, cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal!important;' }, },
{
name: 'UploadDate', index: 'UploadDate', width: 80, fixed: true, sorttype: 'date', formatter: 'date', formatoptions: { srcformat: 'm/d/Y', newformat: 'm/d/Y' },
align: 'center'
}
],
rowNum: 20,
rowList: [20, 50, 100, 200],
pager: '#UploadPager',
caption: '#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Title',
viewrecords: true,
height: 'auto',
width: 770,
hidegrid: false,
shrinkToFit: true,
scrollOffset: 0,
headertitles: true,
loadError: function (xhr, status, error) {
alert(status + " " + error);
},
//onPaging: function (pgButton) {
// $("#RptUpload").jqGrid("setGridParam", { postData: { bReload: false } });
//},
loadCompete: function () {
$("#RptUpload").jqGrid("setGridParam", { datatype: 'json', postData: { bReload: false } });
}
});
mygrid.navGrid('#UploadPager', { edit: false, add: false, del: false, search: false, refresh: false });
isGridDefined = true;
}
$("#rptRefresh").click(function (e) {
e.preventDefault();
var Form = $("form[id='FrmDMEUploadDetails']");
Form.validate();
if (Form.valid()) {
RemoveValidatioMessages();
$("#gridContainer").show();
var Year = $("#Year").val();
var Month = $("#Month").val();
if (!isGridDefined)
DefineGrid(Year, Month);
else
$("#RptUpload").jqGrid("setGridParam", { datatype: "json", page: 1, postData: { bReload: true, Year: Year, Month: Month } }).trigger("reloadGrid");
}
else {
$("#RptUpload").clearGridData();
$("#gridContainer").hide();
}
$(".chzn-select-deselect").trigger("liszt:updated");
return false;
});
});
& my action method is as follows
public ActionResult DMEUploadDetailsList(bool bReload, string Year, string Month, string nd, int rows, int page, string sidx, string sord, string filters)
{
DataSet SearchResult = null;
List<ReportData> ResultRows = new List<ReportData>();
JQGridResult Result = new JQGridResult();
if (bReload)
{
SearchResult = DB.ExecuteDataset("ConnectionString", "pc_GetUploadDetail",
new SqlParameter("#Year", Year),
new SqlParameter("#Month", Month));
Common.SetSession(SearchResult, null, "DMEUploadByMonth");
}
else
SearchResult = SessionManager.GetSession().GetAttribute("DMEUploadByMonth") as DataSet;
if (SearchResult != null)
{
DataTable dtSearchResult = SearchResult.Tables[0];
# region Handle server side Filtering, sorting and paging
int totalRecords = dtSearchResult.Rows.Count; //before paging
int totalPages = (int)Math.Ceiling((decimal)totalRecords / (decimal)rows); //--- number of pages
int startIndex = ((page > 0 ? page - 1 : 0) * rows);
if (sidx != "")
{
dtSearchResult.DefaultView.Sort = sidx + " " + sord;
dtSearchResult = dtSearchResult.DefaultView.ToTable();
}
# endregion
for (int i = startIndex; i < dtSearchResult.Rows.Count; i++)
{
ResultRows.Add(new ReportData()
{
ReadingID = Convert.ToInt32(dtSearchResult.Rows[i][0]),
CompanyName = Convert.ToString(dtSearchResult.Rows[i][1]),
PatientID = Convert.ToInt32(dtSearchResult.Rows[i][2]),
PatientName = Convert.ToString(dtSearchResult.Rows[i][3]),
DOB = (dtSearchResult.Rows[i][4] != DBNull.Value ? Convert.ToDateTime(dtSearchResult.Rows[i][4]) : (DateTime?)null),
InsuranceType = Convert.ToString(dtSearchResult.Rows[i][5]),
UploadDate = (dtSearchResult.Rows[i][6] != DBNull.Value ? Convert.ToDateTime(dtSearchResult.Rows[i][6]) : (DateTime?)null)
});
if (ResultRows.Count == rows) break;
}
Result.DataRows = ResultRows;
Result.page = page;
Result.total = totalPages;
Result.records = totalRecords;
}
return Json(Result, JsonRequestBehavior.AllowGet);
}
The problem with current implementation is that my action method DMEUploadDetailsList is not getting called though view model object is getting passed to request successfuly.
& This implementation were working fine when used client side paging & sorting.
Please suggest me If I am missing anything or correct my mistakes to get server side paging & sorting working.
This grid is defined or reloaded on refresh button. Now what I want is to identify whether action method is called on refresh button click or paging & sorting operation?
[ Now I would like to describe the last two sentence of problem statement. It specifies that when my page is loaded grid is not defined. As soon as I select filter & clicks refresh button my grid is defined for first time & reloaded for subsequent clicks of refresh. If you go through the action method code you will see that i am trying to use bReload bit variable for, when it is true [in case of refresh button click] I would like to query data from SQL otherwise from dataset stored in session [in case of paging or sorting request]. Now If you looked at the postData parameter in definition or in reload call I am passing breload as true. Where as I am not aware of how can I override this parameter to false when user request for sorting & paging. Or else if there is any another simple way with which in action method I can get whether this request is of load data or paging & sorting.]
Sorry, but I don't see any implementation of paging in your code. You calculate the number of records which need be skipped and save it in startIndex, but you don't use startIndex later. Your current code just get data from DataTable and returns all items of the table. You need to skip startIndex items. For example you can start for loop from i = startIndex instead of i = 0.
In general it would be more effective to construct SELECT statement in SqlCommand which uses TOP construct or use STORED PROCEDURE like described in the answer (see another answer too). In the way your server code will get from the SQL server only one page of data instead of fetching all records of data and returning only one page.
UPDATED: I would rewrite your client code to something like the following
$(document).ready(function () {
var templateDate = {
width: 80,
fixed: true,
sorttype: "date",
formatter: "date",
formatoptions: { srcformat: "m/d/Y", newformat: "m/d/Y" }
},
templateInt = { width: 55, fixed: true, sorttype: "integer" },
templateText = {
width: 200,
cellattr: function () {
return 'style="white-space: normal!important;'
}
},
mygrid = $("#RptUpload");
// create the grid without filling it (datatype: "local")
mygrid.jqGrid({
datatype: "local", // to revent initial loading of the grid
postData: {
bReload: true,
Year: function () { return $("#Year").val(); },
Month: function () { return $("#Month").val(); }
},
url: '#Url.Action("DMEUploadDetailsList", "Reports")',
jsonReader: { repeatitems: false, root: "DataRows" },
colNames: [ "#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_OrderID",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_CompanyName",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientID",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientName",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_DOB",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Insurance",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_UploadDate"
],
colModel: [
{ name: "ReadingID", template: templateInt },
{ name: "CompanyName", template: templateText },
{ name: "PatientID", template: templateInt },
{ name: "PatientName", template: templateText },
{ name: "DOB", template: templateDate },
{ name: "InsuranceType", width: 150, template: templateText },
{ name: "UploadDate", template: templateDate }
],
cmTemplate: { align: "center" },
rowNum: 20,
rowList: [20, 50, 100, 200],
pager: "#UploadPager",
caption: "#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Title",
viewrecords: true,
height: "auto",
width: 770,
hidegrid: false,
headertitles: true,
loadError: function (xhr, status, error) {
alert(status + " " + error);
}
});
mygrid.navGrid("#UploadPager",
{ edit: false, add: false, del: false, search: false, refresh: false });
mygrid.closest(".ui-jqgrid").hide(); // hide the grid
$("#rptRefresh").click(function (e) {
var Form = $("form[id=FrmDMEUploadDetails]");
e.preventDefault();
Form.validate();
if (Form.valid()) {
RemoveValidatioMessages();
mygrid.jqGrid("setGridParam", { datatype: "json" })
.trigger("reloadGrid", [{page: 1}])
.closest(".ui-jqgrid").show(); // show the grid;
} else {
mygrid.clearGridData();
mygrid.closest(".ui-jqgrid").hide(); // hide the grid
}
$(".chzn-select-deselect").trigger("liszt:updated");
return false;
});
});
The grid will be created with datatype: "local", so the url and postData will be ignored. After that it seems to me the usage of bReload property in postData and on the server side seems me unneeded. Nevertheless I included bReload still in the JavaScript code till you remove it from the server code.
Additionally I simplified the colModel by usage of column templates (cmTemplate option of jqGrid and template property of colModel). See the old answer for more information. I removed also some unneeded options of jqGrid which values are default (see "Default" column in the documentation of options).
About usage of new versions of STORED PROCEDURE (pc_GetUploadDetail in your code) you can consider to introduction new version (like pc_GetUploadDetailPaged) which supports more parameters. It will not break existing code which uses the old procedure, but you can still use sorting and paging of data on SQL Server instead of getting all query results to web server and implementing sorting and paging in C#.
I solved my initial problem of jqGrid url not getting called by removing Form.serialize() as postData parameter in jqGrid definition & reload calles. This problem was not related to server side sorting & paging. This was caused due to my previous postData parameter definition as Form.serialize(). Instead I used pass individual parameters to the postData array.
My next problem was related to sorting & paging at server side. In which I want to fetch data from session dataset when user page through the grid or want to sort the grid data; otherwise reload new data by querying SQL server.
According to Oleg answer I must have adopted the simplified way of doing paging & sorting at SQL end instead of in c#. But I was not allowed to add new version of stored procedure as per Oleg suggestion. So I stick to use extra parameter in postData array named operCode like this in grid definition.
postData: {
operCode: "Reload",
Year: function () { return $("#Year").val(); },
InsuranceID: function () { return $("#InsuranceType").val(); },
CustomerID: function () { return $("#CompanyName").val(); }
},
Now I added onPaging & onSortCol event to override operCode postData parameter value like this
onPaging: function (pgButton) {
mygrid.jqGrid("setGridParam", { datatype: 'json', postData: { operCode: "Paging" } });
},
onSortCol: function (index, iCol, sortorder) {
mygrid.jqGrid("setGridParam", { datatype: 'json', postData: { operCode: "Sorting" } });
}
Now whenever user clicks refresh button operCode is sent as Reload, on paging as "Paging" & on sorting as "Sorting"
My server side action method code is as follows
public ActionResult DMEUploadDetails(string operCode, string Year, string Month, string nd, int rows, int page, string sidx, string sord, string filters)
{
DataSet SearchResult = null;
List<ReportData> ResultRows = new List<ReportData>();
JQGridResult Result = new JQGridResult();
if (operCode == "Reload")
{
SearchResult = DB.ExecuteDataset("ConnectionString", "pc_GetUploadDetail",
new SqlParameter("#Year", Year),
new SqlParameter("#Month", Month));
Common.SetSession(SearchResult, null, "POXMonthlyUploads");
}
else
SearchResult = (SessionManager.GetSession().GetAttribute("POXMonthlyUploads") as System.Web.UI.WebControls.GridView).DataSource as DataSet;
if (SearchResult != null)
{
DataTable dtSearchResult = SearchResult.Tables[0];
# region Handle server side Filtering, sorting and paging
int totalRecords = dtSearchResult.Rows.Count; //before paging
int totalPages = (int)Math.Ceiling((decimal)totalRecords / (decimal)rows); //--- number of pages
int startIndex = ((page > 0 ? page - 1 : 0) * rows);
if (sidx != "" && operCode == "Sorting")
{
dtSearchResult.DefaultView.Sort = sidx + " " + sord;
dtSearchResult = dtSearchResult.DefaultView.ToTable();
SearchResult.Tables.RemoveAt(0);
SearchResult.Tables.Add(dtSearchResult);
Common.SetSession(SearchResult, null, "POXMonthlyUploads");
}
# endregion
for (int i = startIndex; i < dtSearchResult.Rows.Count; i++)
{
ResultRows.Add(new ReportData()
{
//code to fill data to structure object
});
if (ResultRows.Count == rows) break;
}
Result.DataRows = ResultRows;
Result.page = page;
Result.total = totalPages;
Result.records = totalRecords;
}
return Json(Result, JsonRequestBehavior.AllowGet);
}
Very much Thanks to Oleg for giving me some extra knowledge about jqGrid & giving me good idea about server side paging & sorting.