I have the following JQGrid table, which is being generated from JSON data. I want to be able to generate/export or create a pdf file based on the table data state that is view able. I am using JSON , Jqgrid and Javascript
How do I generate a pdf file from the data ?
Here My FIDDLE
JS CODE
$(document).ready(function() {
var jsonData = {
"Name": "Julie Brown",
"Account": "C0010",
"LoanApproved": "12/5/2015",
"LastActivity": "4/1/2016",
"PledgedPortfolio": "4012214.00875",
"MaxApprovedLoanAmt": "2050877.824375",
"LoanBalance": "1849000",
"AvailableCredit": "201877.824375",
"Aging": "3",
"Brokerage": "My Broker",
"Contact": "Robert L. Johnson",
"ContactPhone": "(212) 902-3614",
"RiskCategory": "Yellow",
"rows": [{
"ClientID": "C0010",
"Symbol": "WEC",
"Description": "Western Electric Co",
"ShareQuantity": "20638",
"SharePrice": "21.12",
"TotalValue": "435874.56",
"LTVCategory": "Equities",
"LTVRatio": "50%",
"MaxLoanAmt": "217937.28"
}, {
"ClientID": "C0010",
"Symbol": "BBB",
"Description": "Bins Breakers and Boxes",
"ShareQuantity": "9623",
"SharePrice": "74.29125",
"TotalValue": "714904.69875",
"LTVCategory": "Equities",
"LTVRatio": "50%",
"MaxLoanAmt": "357452.349375"
}, {
"ClientID": "C0010",
"Symbol": "GPSC",
"Description": "Great Plains Small Cap Stock",
"ShareQuantity": "49612",
"SharePrice": "14.24",
"TotalValue": "706474.88",
"LTVCategory": "Mutual Funds - Small Cap",
"LTVRatio": "40%",
"MaxLoanAmt": "282589.952"
}]
},
mmddyyyy = "";
/*********************************************************************/
$("#output").jqGrid({
url: "/echo/json/",
mtype: "POST",
datatype: "json",
postData: {
json: JSON.stringify(jsonData)
},
colModel: [
/** { name: 'ClientID', label:'ClientID',width: 80, key: true },****/
{
name: 'Symbol',
width: 65
}, {
name: 'Description',
width: 165
}, {
name: 'ShareQuantity',
align: 'right',
width: 85,
classes: "hidden-xs", labelClasses: "hidden-xs",
formatter: 'currency',
formatoptions: {
prefix: " ",
suffix: " "
}
}, {
name: 'SharePrice',
label: 'Share Price',
align: 'right',
width: 100,
classes: "hidden-xs", labelClasses: "hidden-xs",
template: "number",
formatoptions: {
prefix: " $",
decimalPlaces: 4
}
},
/*{ label: 'Value1',
name: 'Value1',
width: 80,
sorttype: 'number',
formatter: 'number',
align: 'right'
}, */
{
name: 'TotalValue',
label: 'Total Value',
width: 160,
sorttype: 'number',
align: "right",
search: false,
formatter: 'currency',
formatoptions: {
prefix: " $",
suffix: " "
}
}, {
name: 'LTVRatio',
label: 'LTV Ratio',
width: 70,
sorttype: 'number',
align: "right",
formatter: 'percentage',
formatoptions: {
prefix: " ",
suffix: " "
}
}, {
name: 'LTVCategory',
label: 'LTV Category',
classes: "hidden-xs", labelClasses: "hidden-xs",
width: 120,
width: 165
},
{
name: 'MaxLoanAmt',
label: 'MaxLoanAmount',
width: 165,
sorttype: 'number',
align: "right",
search: false,
formatter: 'currency',
formatoptions: {
prefix: " $",
suffix: " "
}
}
],
additionalProperties: ["Symbol", "Description"],
subGrid: true,
subGridRowExpanded: function (subgridDivId, rowid) {
var item = $(this).jqGrid("getLocalRow", rowid);
$("#" + $.jgrid.jqID(subgridDivId)).html("Symbol: <em>" + item.Symbol +
"</em><br/>Description: <em>" + item.Description + "</em>");
},
beforeProcessing: function (data) {
var symbolsMap = {}, symbolsValues = ":All", rows = data.rows, i, symbol;
for (i = 0; i < rows.length; i++) {
symbol = rows[i].Symbol;
if (!symbolsMap.hasOwnProperty(symbol)) {
symbolsMap[symbol] = 1;
symbolsValues += ";" + symbol + ":" + symbol;
}
}
$(this).jqGrid("setColProp", 'Symbol', {
stype: "select",
searchoptions: {
value: symbolsValues
}
}).jqGrid('destroyFilterToolbar')
.jqGrid('filterToolbar', {
stringResult: true,
searchOnEnter: false,
defaultSearch : "cn"
});
},
/*beforeProcessing: function (data) {
var item, i, n = data.length;
for (i = 0; i < n; i++) {
item = data[i];
item.Quantity = parseFloat($.trim(item.Quantity).replace(",", ""));
item.LTVRatio = parseFloat($.trim(item.LTVRatio *10000).replace(",", ""));
item.Value = parseFloat($.trim(item.Value).replace(",", ""));
item.Num1 = parseInt($.trim(item.Num1).replace(",", ""), 10);
item.Num2 = parseInt($.trim(item.Num2).replace(",", ""), 10);
}
}, */
iconSet: "fontAwesome",
loadonce: true,
rownumbers: true,
cmTemplate: {
autoResizable: true,
editable: true
},
autoResizing: {
compact: true
},
autowidth: true,
height: 'auto',
forceClientSorting: true,
sortname: "Symbol",
footerrow: true,
caption: "<b>Collateral Value</b> <span class='pull-right' style='margin-right:20px;'>Valuation as of: " + mmddyyyy + "</span>",
loadComplete: function() {
var $self = $(this),
sum = $self.jqGrid("getCol", "Price", false, "sum"),
sum1 = $self.jqGrid("getCol", "MaxLoanAmt", false, "sum");
//ltvratio = $self.jqGrid("getCol","LTVRatio:addas", "Aved Loan Amount");
$self.jqGrid("footerData", "set", {
LTVCategory: "Max Approved Loan Amount:",
Price: sum,
MaxLoanAmt: sum1
});
}
});
$("#output").jqGrid('filterToolbar', {stringResult: true, searchOnEnter: false, defaultSearch : "cn"});
$(window).on("resize", function () {
var newWidth = $("#output").closest(".ui-jqgrid").parent().width();
$("#output").jqGrid("setGridWidth", newWidth, true);
}).triggerHandle("resize");
});
There is no build in method to export jqgrid data to pdf. You have to use third party tools( I personally like iTextSharp which can be downloaded from Here . You have to create action method for printing the grid data in your controller.
Here is also another one example one guy made.
Here is also another example in trirand. If you see the source code they are using iTextHsarp.
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JQGridMVCExamples.Models;
using Trirand.Web.Mvc;
using System.IO;
//
// For PDF export we are using the free open-source iTextSharp library.
//
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Data;
namespace JQGridMVCExamples.Controllers.Grid
{
public partial class GridController : Controller
{
// This is the default action for the View. Use it to setup your grid Model.
public ActionResult ExportPDF()
{
// Get the model (setup) of the grid defined in the /Models folder.
var gridModel = new OrdersJqGridModel();
var ordersGrid = gridModel.OrdersGrid;
// Setting the DataUrl to an action (method) in the controller is required.
// This action will return the data needed by the grid
ordersGrid.DataUrl = Url.Action("PDFGrid_DataRequested");
// customize the default Orders grid model with custom settings
// NOTE: you need to call this method in the action that fetches the data as well,
// so that the models match
SetPDFExportGrid(ordersGrid);
// Pass the custmomized grid model to the View
return View(gridModel);
}
// This method is called when the grid requests data
public JsonResult PDFGrid_DataRequested()
{
// Get both the grid Model and the data Model
// The data model in our case is an autogenerated linq2sql database based on Northwind.
var gridModel = new OrdersJqGridModel();
var northWindModel = new NorthwindDataContext();
// customize the default Orders grid model with our custom settings
SetPDFExportGrid(gridModel.OrdersGrid);
// Save the current grid state in Session
// We will later need it for PDF Export
JQGridState gridState = gridModel.OrdersGrid.GetState();
Session["gridState"] = gridState;
// return the result of the DataBind method, passing the datasource as a parameter
// jqGrid for ASP.NET MVC automatically takes care of paging, sorting, filtering/searching, etc
return gridModel.OrdersGrid.DataBind(northWindModel.Orders);
}
public JsonResult PDFExport_AutoCompleteShipName(string term)
{
var northWindModel = new NorthwindDataContext();
JQAutoComplete autoComplete = new JQAutoComplete();
autoComplete.DataField = "ShipName";
autoComplete.AutoCompleteMode = AutoCompleteMode.BeginsWith;
autoComplete.DataSource = from o in northWindModel.Orders
select o;
return autoComplete.DataBind();
}
private void SetPDFExportGrid(JQGrid ordersGrid)
{
// show the search toolbar
ordersGrid.ToolBarSettings.ShowSearchToolBar = true;
ordersGrid.ToolBarSettings.ShowSearchButton = true;
var orderDateColumn = ordersGrid.Columns.Find(c => c.DataField == "OrderDate");
orderDateColumn.DataFormatString = "{0:yyyy/MM/dd}";
orderDateColumn.SearchType = SearchType.DatePicker;
orderDateColumn.DataType = typeof(DateTime);
orderDateColumn.SearchControlID = "DatePicker";
orderDateColumn.SearchToolBarOperation = SearchOperation.IsEqualTo;
var shipNameColumn = ordersGrid.Columns.Find(c => c.DataField == "ShipName");
shipNameColumn.SearchType = SearchType.AutoComplete;
shipNameColumn.DataType = typeof(string);
shipNameColumn.SearchControlID = "AutoComplete";
shipNameColumn.SearchToolBarOperation = SearchOperation.Contains;
var orderIDColumns = ordersGrid.Columns.Find(c => c.DataField == "OrderID");
orderIDColumns.Searchable = true;
orderIDColumns.DataType = typeof(int);
orderIDColumns.SearchToolBarOperation = SearchOperation.IsEqualTo;
SetPDFCustomerIDSearchDropDown(ordersGrid);
SetPDFFreightSearchDropDown(ordersGrid);
}
private void SetPDFCustomerIDSearchDropDown(JQGrid ordersGrid)
{
// setup the grid search criteria for the columns
JQGridColumn customersColumn = ordersGrid.Columns.Find(c => c.DataField == "CustomerID");
customersColumn.Searchable = true;
// DataType must be set in order to use searching
customersColumn.DataType = typeof(string);
customersColumn.SearchToolBarOperation = SearchOperation.IsEqualTo;
customersColumn.SearchType = SearchType.DropDown;
// Populate the search dropdown only on initial request, in order to optimize performance
if (ordersGrid.AjaxCallBackMode == AjaxCallBackMode.RequestData)
{
var northWindModel = new NorthwindDataContext();
var searchList = from customers in northWindModel.Customers
select new SelectListItem
{
Text = customers.CustomerID,
Value = customers.CustomerID
};
customersColumn.SearchList = searchList.ToList<SelectListItem>();
customersColumn.SearchList.Insert(0, new SelectListItem { Text = "All", Value = "" });
}
}
private void SetPDFFreightSearchDropDown(JQGrid ordersGrid)
{
// setup the grid search criteria for the columns
JQGridColumn freightColumn = ordersGrid.Columns.Find(c => c.DataField == "Freight");
freightColumn.Searchable = true;
// DataType must be set in order to use searching
freightColumn.DataType = typeof(decimal);
freightColumn.SearchToolBarOperation = SearchOperation.IsGreaterOrEqualTo;
freightColumn.SearchType = SearchType.DropDown;
// Populate the search dropdown only on initial request, in order to optimize performance
if (ordersGrid.AjaxCallBackMode == AjaxCallBackMode.RequestData)
{
List<SelectListItem> searchList = new List<SelectListItem>();
searchList.Add(new SelectListItem { Text = "> 10", Value = "10" });
searchList.Add(new SelectListItem { Text = "> 30", Value = "30" });
searchList.Add(new SelectListItem { Text = "> 50", Value = "50" });
searchList.Add(new SelectListItem { Text = "> 100", Value = "100" });
freightColumn.SearchList = searchList.ToList<SelectListItem>();
freightColumn.SearchList.Insert(0, new SelectListItem { Text = "All", Value = "" });
}
}
public ActionResult ExportToPDF(string exportType)
{
var gridModel = new OrdersJqGridModel();
var northWindModel = new NorthwindDataContext();
var grid = gridModel.OrdersGrid;
// Get the last grid state the we saved before in Session in the DataRequested action
JQGridState gridState = Session["GridState"] as JQGridState;
// Need to set grid options again
SetExportGrid(grid);
if (String.IsNullOrEmpty(exportType))
exportType = "1";
DataTable exportData;
switch (exportType)
{
case "1":
grid.ExportSettings.ExportDataRange = ExportDataRange.All;
exportData = grid.GetExportData(northWindModel.Orders);
ExportToPDF(exportData);
break;
case "2":
grid.ExportSettings.ExportDataRange = ExportDataRange.Filtered;
exportData = grid.GetExportData(northWindModel.Orders, gridState);
ExportToPDF(exportData);
break;
case "3":
grid.ExportSettings.ExportDataRange = ExportDataRange.FilteredAndPaged;
exportData = grid.GetExportData(northWindModel.Orders, gridState);
ExportToPDF(exportData);
break;
}
return View();
}
private void ExportToPDF(DataTable dt)
{
//
// For PDF export we are using the free open-source iTextSharp library.
//
Document pdfDoc = new Document();
MemoryStream pdfStream = new MemoryStream();
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDoc, pdfStream);
pdfDoc.Open();//Open Document to write
pdfDoc.NewPage();
Font font8 = FontFactory.GetFont("ARIAL", 7);
PdfPTable PdfTable = new PdfPTable(dt.Columns.Count);
PdfPCell PdfPCell = null;
//Add Header of the pdf table
for (int column = 0; column < dt.Columns.Count; column++)
{
PdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Columns[column].Caption, font8)));
PdfTable.AddCell(PdfPCell);
}
//How add the data from datatable to pdf table
for (int rows = 0; rows < dt.Rows.Count; rows++)
{
for (int column = 0; column < dt.Columns.Count; column++)
{
PdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows][column].ToString(), font8)));
PdfTable.AddCell(PdfPCell);
}
}
PdfTable.SpacingBefore = 15f; // Give some space after the text or it may overlap the table
pdfDoc.Add(PdfTable); // add pdf table to the document
pdfDoc.Close();
pdfWriter.Close();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition", "attachment; filename=gridexport.pdf");
Response.BinaryWrite(pdfStream.ToArray());
Response.End();
}
}
}
Related
A was using DataTables plugin, and when displaying my columns I needed to put the first letter to LowerCase for it to recognize the property/object, e.g:
// Object name is actually: EngineeringChange.Responsible
{
title: "Responsible",
data: "engineeringChange.responsible",
className: "columnName columnHeader",
},
I just assumed the first letter would always be capitalized to LowerCase. I tried creating a new property inside EngineeringChange named ECRNumber, so I tried:
{
title: "ECR Number",
data: "engineeringChange.eCRNumber",
className: "columnName columnHeader",
},
Isn't recognized as a parameter... After a bit of searching I find out the Json response I get on AJAX it's called ecrNumber. So now I'm actually lost on which are the rules that are automatically applied to the Json Response. How does it turn ecr to LowerCase and Number to UpperCase (the N)??
Edit
Sry, can´t think of any easy way to exactly reproduce my problem on a demo
TableDesign/Creation
table = $('#tblEntries2').DataTable({
order: [[0, 'desc']],
deferRender: true,
ajax: {
url: '#Url.Action("GetEntries", "AlteracaoEngenharia")',
method: 'GET',
dataSrc: '',
beforeSend: function () {
onBegin();
$content.hide();
$loader.show();
},
complete: function (jsonResponse) {
console.log(jsonResponse);
onComplete();
$loader.hide();
$content.fadeIn();
$('#ExcelExport').show();
table.column(5).visible(false);
table.column(6).visible(false);
table.column(7).visible(false);
table.column(9).visible(false);
table.column(10).visible(false);
table.column(11).visible(false);
}
},
dom: "<'row'<'col-2'l><'col-7 text-center'B><'col-3'f>>" +
"<'row'<'col-12'tr>>" +
"<'row'<'col-5'i><'col-7'p>>",
lengthMenu: [
[10, 25, 50, 100, -1],
['10', '25', '50', '100', 'Todos'],
],
columns: [
{
title: "Id (yr-id)",
data: "creationYear",
className: "columnNumber columnHeader",
},
{
title: "ECR Number",
data: "engineeringChange.ecrNumber",
className: "columnNumber columnHeader",
},
{
title: "Criador Alteração de Engenharia",
data: "engineeringChange.responsible",
className: "columnName columnHeader",
},
...
Handler
public IActionResult GetEntries()
{
GetDataEntries();
int count = 0;
int currentYear = 0;
foreach (var entry in EntriesList)
{
EngineeringChangesListViewModel h = new EngineeringChangesListViewModel
{
EngineeringChange = entry
};
if (currentYear != entry.DataCriacao.Year)
{
count = 1;
currentYear = entry.DataCriacao.Year;
}
else
{
count++;
}
h.DeadLine = entry.FinishedGood.Week + " - " + entry.DataCriacao.Year.ToString();
if (entry.OldPart == null)
{
h.EngineeringChange.OldPart = new Part();
}
if (entry.NewPart == null)
{
h.EngineeringChange.NewPart = new Part();
}
if (entry.FinishedGood == null)
{
h.EngineeringChange.FinishedGood = new FinishedGood();
}
if (entry.OldPart != null && entry.OldPart.CDP.HasValue)
h.OldPartValue = entry.OldPart.CDP * entry.OldPart.Stock;
if (entry.NewPart != null && entry.NewPart.CDP.HasValue)
h.NewPartValue = entry.NewPart.CDP * entry.NewPart.Stock;
h.EngineeringChange.ECRNumber = entry.ECRNumber;
//toString("D4") padds the number to always be 4 digits
h.CreationYear = entry.DataCriacao.Year.ToString() + "_" + count.ToString("D4");
h.IdYear = count;
EntriesListaViewModel.Add(h);
}
var errorsJson = JsonConvert.SerializeObject(EntriesListaViewModel);
Console.WriteLine(errorsJson);
return new JsonResult(EntriesListaViewModel);
}
HANDLER OUTPUT
[{"CreationYear":"2021_0001","IdYear":1,"OldPartValue":null,"NewPartValue":2061.09155,"DeadLine":"15 - 2021","EngineeringChange":{"Id":8,"DataCriacao":"2021-03-11T16:15:24.6630956","Responsible":"José António","ECRNumber":"X1232","State":"Aberto","Comment":"Teste","UserId":1,"User":null,"Component":null,"FinishedGood":{"Id":31,"Week":15,"EngineeringChangeId":8},"OldPart":{"Id":5,"Reference":"FS12848AC","Stock":null,"CDP":1.43584776,"LastExpired":null},"NewPart":{"Id":6,"Reference":"FS12848AD","Stock":1650,"CDP":1.24914646,"LastExpired":"2021-03-11T00:00:00"},"Transformation":{"Id":188,"Possible":true,"Cost":1090.0,"WillBeTransformed":true,"TransformationDate":"2021-03-13T08:48:00","Responsible":"Miguel","EngineeringChangeId":8}}},]
PAGE/AJAX OUTPUT outputs are created by console.log() and Console.WriteLine() displayed above.
ECRNumber gets named to ecrNumber...
I show jstree in ui and fill it whith json from asp.net server side code ,it's work good but when i have one node with two parent its dont work well.
Could i show jstree that has one node with two parent?
when i do this its get show error.
its cut child between two parent!
I know its not tree role but i need it.
$(function () {
$('#jstree').jstree({
'core': {
"animation": 0,
"check_callback": true,
"themes": { "stripes": true },
'data': {
'url': '/Products/ProductCategoryStructure/GetData',
'data': function (node) {
return { 'id': node.id };
}
}
},
"types": {
"#": {
"max_children": 1,
"max_depth": 4,
"valid_children": ["root"]
},
"default": {
"valid_children": ["default", "file"]
},
"file": {
"icon": "glyphicon glyphicon-file",
"valid_children": []
}
},
plugins: ["contextmenu"], contextmenu: {items: customMenu}
});
$('#jstree').on('changed.jstree', function (e, data) {
var i, j, r = [];
for (i = 0, j = data.selected.length; i < j; i++) {
r.push(data.instance.get_node(data.selected[i]).text);
}
//alert('Selected: ' + r.join(', '));
// $('#event_result').html('Selected: ' + r.join(', '));
}).jstree();
});
It's Server Side Code
[HttpGet]
public ActionResult GetData()
{
var ListProductCategoryStructure = _service.GetAll();
var nodes = new List<JsTreeModel>();
//nodes.Add(new JsTreeModel() { id = "58", parent = "#", text = " مادیران مال",opened=true,icon="/assets/pages/img/mlgo.png" });
nodes.Add(new JsTreeModel() { id = "1", parent = "#", text = " مادیران مال", opened = true, icon = "/assets/pages/img/mlgo.png" });
foreach (var item in ListProductCategoryStructure)
{
nodes.Add(new JsTreeModel() { id = item.ProductCategoryId.ToString(), parent = (item.ProductParentCategoryId==65?"#": item.ProductParentCategoryId.ToString()), text = item.ProductParentCategoryTitle,icon="false" });
}
return Json(nodes, JsonRequestBehavior.AllowGet);
}
and it's result
One node can have only one parent.
I have a JS view in which I am creating a sap.m.Table. It's "columns" are bound to a JSONModel. It's "items" are bound to ODataModel. I want to access the row data and the column name when I click on an Icon contained in the ColumnListItem.
View code:
createContent : function(oController) {
var oTable = new sap.m.Table("table1", {
width: "auto",
noDataText: "Please add rows to be displayed!"
}).addStyleClass("sapUiResponsiveMargin");
oTable.bindAggregation("columns", "Periods>/periods", function(sId, oContext) {
var sColumnId = oContext.getObject().period;
return new sap.m.Column({
hAlign: "Center",
vAlign: "Middle",
header: new sap.m.Text({
text: sColumnId
})
});
});
oTable.bindItems("zStatus>/StatusSet", function(sId, oContext) {
var row = new sap.m.ColumnListItem(sId, {
type : "Inactive",
cells: [
new sap.ui.core.Icon({
src: "sap-icon://delete",
hoverColor: "red",
activeColor: "red",
press: [oController.onDeleteIconPress, oController]
}),
new sap.m.Text({
text: "{zStatus>Description}"
}),
new sap.ui.core.Icon(sId, {
src: {
path: "zStatus>Status1",
formatter: function(status) {
switch(status) {
case "R":
return "sap-icon://sys-cancel";
case "G":
return "sap-icon://sys-enter";
case "Y":
return "sap-icon://notification";
default:
return "sap-icon://sys-help";
}
}
},
size: "1.5em",
press: [oController.onStatusIconPress, oController]
}) ]
});
return oTable;
}
In my controller I create an array, then a JSON model "Periods" from it and set it to this view. Odata model "zStatus" is defined in manifest file.
Controller code:
onInit : function() {
// array aPeriods is populated first then
var oPeriodsModel = new sap.ui.model.json.JSONModel();
oPeriodsModel.setData({
periods : aPeriods
});
this.getView().setModel(oPeriodsModel, "Periods");
},
onStatusIconPress : function(oEvent) {
// I can get the row data on icon press
// Problem 2: but how do I get the column name?
// I wanted to attach the column name to icon as customData but I could
// not access model attached to columns inside bindItems method
}
I managed to solve it myself.
Created an array in createContent. Filled it with column IDs in bindAggregation of columns and then used this array in bindItems method.
Then I can pass customData to icons.
Here is the code -
createContent : function(oController) {
var aColumns = []; // array to store column ids
var columnIndex = 0; // index to track
//more code
// create table oTable
oTable.bindAggregation("columns", "/columns", function(sId, oContext) {
var sColumnId = oContext.getObject().period;
if (sColumnId === "DeleteIcon") {
// this is always my first column
columnIndex = 0;
return new sap.m.Column({
hlign : "Begin",
vAlign : "Middle",
width : "2em",
header : new sap.m.Text({
text : ""
})
});
} else {
// add column ids to array
aColumns[columnIndex++] = sColumnId;
return new sap.m.Column({
hlign : "Center",
vAlign : "Middle",
header : new sap.m.Text({
text : sColumnId
})
});
}
});
oTable.bindItems("/rows", function(sId, oContext) {
var row = new sap.m.ColumnListItem({
new sap.m.Text({
text: "{Name}"
}),
new sap.ui.core.Icon(sId, {
src: "sap-icon://sys-help"
size: "1.5em",
press: [oController.onStatusIconPress, oController],
customData : [
// use column ids here
new sap.ui.core.CustomData({key: "column", value: aColumns[0]})
]
}),
});
return row;
}
}
I am using Kendo() grid in my application which has binding with an model.
I want to provide Upload control in Grid against each row. Please see razor view design as follows:
<div id="processDetailGrid"></div>
var processDetailGrid
, processDetailDataSource
, processDetailToolbar
, projectComboBox;
$(function () {
ProcessDetailToolbar = $("#processDetailToolbar").kendoToolBar({items: [{ id: "processDetailAdd", type: "button", spriteCssClass: "fa fa-plus-square", text: "Add", overflow: "never", click: processDetailAdd }]}).data("kendoToolBar");
function processDetailAdd() {
processDetailGrid.addRow();}
processDetailGrid = $("#processDetailGrid").kendoGrid({
dataSource: processDetailDataSource,
height: '98%',
selectable: "cell",
resizable: true,
reorderable: true,
columnMenu: true,
editable: false,
columns: [
{
field: "SoftwareUpLoad",
title: "#Resource.Field_SoftwareUpLoad",
template: kendo.template($("#template").html()),
// template: '#= SoftwareUpLoad==""?"<input type=\'file\' show=\'0\' name=\'files\' />":"<a class=\'k-button\' href=\'GetFiles?key=SoftwareUpLoad\'>Download</a>"#',
width: 300
},
{
field: "CutterCode",
title: "CutterCode",
width: 200
}
],
dataBound: function (e) {
var grid = this;
var firstItem = this.dataSource.view()[0];
this.tbody.find("input[name=files][show=0]").kendoUpload({
multiple: false,
async: {
saveUrl: 'save',
removeUrl: "remove",
autoUpload: true
},
validation: {
allowedExtensions: [".pdf"]
},
upload: function (e) {
var item = grid.dataItem(this.element.closest("tr"));
var id = BillId;
this.element.closest(".k-button").addClass("k-state-disabled");
this.element.closest(".k-button").find("input[name=files]").attr("show", "1");
e.data = { id: id, Operation: item.OperationNO };
},
remove: function (e) {
var item = grid.dataItem(this.element.closest("tr"));
var id = BillId;
this.element.closest(".k-button").removeClass("k-state-disabled");
e.data = { id: id, Operation: item.OperationNO };
},
success: function (e) {
var FileName = e.response.FileName;
var item = grid.dataItem(this.element.closest("tr"));
item.FileName = FileName;
item.dirty = false;
}
});
}
}).data("kendoGrid");
})
In the grid data line I upload data, click on the new line button, upload the data will be automatically emptied,but I want't that, I would like to ask how to do?
I have a project in which I'm using the KendoUI Grid using the server to get the data instead of locally.
I'm not sure what the JSON response should be from my server to get grouping to work however. My goal is when the user drags a column to the grouping header that I know what kind of JSON response to give back so the GRID groups by that column and any other columns that might be added to that header.
Given the image above, how do I create a JSON response to fulfill it (so its showing what its supposed to grouped)? I get I have to do this on my own on the server but not sure how JSON needs to be formated. Furthermore if I want to show a 'count' field next to the groups when they are created so I know how many items are in each group (which I believe is the aggregate?)
My current grid codes looks like the following:
<div id="grid" style="height:100%;"></div>
<script>
$(window).on("resize", function() {
kendo.resize($("#grid"));
});
var crudServiceBaseUrl = "/api",
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/companies",
dataType: "json",
type: "POST"
},
update: {
url: crudServiceBaseUrl + "/companies/update",
dataType: "json",
type: "POST"
},
destroy: {
url: crudServiceBaseUrl + "/companies/destroy",
dataType: "json",
type: "POST"
},
create: {
url: crudServiceBaseUrl + "/companies/create",
dataType: "json",
type: "POST"
},
parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
return {models: kendo.stringify(options.models)};
}
}
},
error: function (e) {
/* the e event argument will represent the following object:
{
errorThrown: "custom error",
errors: ["foo", "bar"]
sender: {... the Kendo UI DataSource instance ...}
status: "customerror"
xhr: null
}
*/
//alert("Status: " + e.status + "; Error message: " + e.errorThrown);
console.log("Status: " + e.status + "; Error message: " + e.errorThrown);
console.log("Errors: " + e.errors.join("; "));
},
autoSync: false,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
serverGrouping: true,
serverAggregates: true,
pageSize: 20,
columnResizeHandleWidth: 6,
schema: {
total: "itemCount",
data: "items",
groups: "groups",
aggregates: "aggregates",
group: {
field: "phone", aggregates: [{ field: "phone", aggregate: "count" }]
},
model: {
id: "id",
fields: {
id: { editable: false, nullable: true },
name: { validation: { required: true } },
phone: {
type: "string",
validation: {
required: true,
phonerule: function(e){
if (e.is("[data-phonerule-msg]"))
{
var input = e.data('kendoMaskedTextBox');
//If we reached the end of input then it will return -1 which means true, validation passed
//Otherwise it won't === -1 and return false meaning all the characters were not entered.
return input.value().indexOf(input.options.promptChar) === -1;
}
return true; //return true for anything else that is not data-phonerule-msg
}
}
},
email: { type: "string", validation: { required: true, email:true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
groupable: true,
sortable: {
mode: "multiple",
allowUnsort: true
},
selectable: "multiple cell",
allowCopy:true,
toolbar: ["create","excel"],
excel: {
fileName: "Kendo UI Grid Export.xlsx",
//Below is only used as fallback for old browsers without support
proxyURL: "//demos.telerik.com/kendo-ui/service/export",
filterable: true
},
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
reorderable: true,
resizable: true,
columnMenu: true,
filterable: true,
editable: "popup",
mobile: true,
columns: [
{
field: "name",
title: "Company Name",
aggregates: ["count"],
groupFooterTemplate: "Count: #=count#"
},
{
field: "phone",
title: "Phone",
editor: function(container, options){
//pattern="[(][0-9]{3}[)] [0-9]{3}-[0-9]{4}"
var input = $('<input type="tel" data-phonerule-msg="Invalid Phone Number!" class="k-textbox" required />');
input.attr("name", options.field);
input.kendoMaskedTextBox({
mask: "(999) 000-0000"
});
input.appendTo(container);
},
aggregates: ["count"],
groupFooterTemplate: "Count: #=count#"
},
{
field: "email",
title: "Email",
editor: function(container, options){
var input = $('<input type="email" data-email-msg="Invalid email!" class="k-textbox" required/>');
input.attr("name", options.field);
input.appendTo(container);
},
aggregates: ["count"],
groupFooterTemplate: "Count: #=count#"
},
{
command: ["edit", "destroy"],
title: "Operations",
width: "240px"
}
],
});
</script>
My current code that generates the demo javascript via Symfony 3.0 is below in..
DefaultController.php
/**
* #Route("/api/companies", name="api_companies_read")
*/
public function apiCompaniesReadAction(Request $request)
{
$data["itemCount"] = "7";
// $tdata["field"] = "";
// $tdata["value"] = "";
// $tdata["items"] = "hey";
// $data["groups"][] = $tdata;
$tdata["id"] = "1";
$tdata["name"] = "Joe";
$tdata["phone"] = "(714)475-8651";
$tdata["email"] = "Joe#whatever.com";
$data["items"][] = $tdata;
$tdata["id"] = "2";
$tdata["name"] = "Rachel";
$tdata["phone"] = "(563)812-4184";
$tdata["email"] = "rachel#yahoo.com";
$data["items"][] = $tdata;
$tdata["id"] = "3";
$tdata["name"] = "John";
$tdata["phone"] = "(563)812-4184";
$tdata["email"] = "John#yahoo.com";
$data["items"][] = $tdata;
$tdata["id"] = "4";
$tdata["name"] = "Richard";
$tdata["phone"] = "(563)812-4184";
$tdata["email"] = "John#yahoo.com";
$data["items"][] = $tdata;
$tdata["id"] = "5";
$tdata["name"] = "Sister";
$tdata["phone"] = "(563)812-4184";
$tdata["email"] = "John#yahoo.com";
$data["items"][] = $tdata;
$tdata["id"] = "6";
$tdata["name"] = "Brother";
$tdata["phone"] = "(563)812-4184";
$tdata["email"] = "Brother#yahoo.com";
$data["items"][] = $tdata;
$tdata["id"] = "7";
$tdata["name"] = "Sibling";
$tdata["phone"] = "(563)812-4184";
$tdata["email"] = "Sibling#yahoo.com";
$data["items"][] = $tdata;
// schema: {
// total: "total",
// model: {
// id: "CompanyID",
// fields: {
// CompanyID: { editable: false, nullable: true },
// Name: { validation: { required: true } },
// Phone: { type: "string" },
// Email: { type: "string" }
// }
// }
// }
// replace this example code with whatever you need
return new JsonResponse($data);
}
The current JSON it creates looks like this.
JSON
{"itemCount":"7","items":[{"id":"1","name":"Joe","phone":"(714)475-8651","email":"Joe#whatever.com"},{"id":"2","name":"Rachel","phone":"(563)812-4184","email":"rachel#yahoo.com"},{"id":"3","name":"John","phone":"(563)812-4184","email":"John#yahoo.com"},{"id":"4","name":"Richard","phone":"(563)812-4184","email":"Richard#yahoo.com"},{"id":"5","name":"Sister","phone":"(563)812-4184","email":"Sister#yahoo.com"},{"id":"6","name":"Brother","phone":"(563)812-4184","email":"Brother#yahoo.com"},{"id":"7","name":"Sibling","phone":"(563)812-4184","email":"Sibling#yahoo.com"}]}
I found an article here that looks close to what I want just hard to understand. This might also help.
I created JSFiddle that can be played around with, just needs to be supplied valid data.
Update
I got server paging to work! The first major change is on the transport for the datasource you have to change the parameterMap to send json so you can access what its trying to tell your server to change.
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: crudServiceBaseUrl + "/companies",
dataType: "json",
type: "POST"
},
update: {
url: crudServiceBaseUrl + "/companies/update",
dataType: "json",
type: "POST"
},
destroy: {
url: crudServiceBaseUrl + "/companies/destroy",
dataType: "json",
type: "POST"
},
create: {
url: crudServiceBaseUrl + "/companies/create",
dataType: "json",
type: "POST"
},
parameterMap: function(options, operation) {
return kendo.stringify(options);
}
},
My datasource looks like above, but you could adjust to your needs. Next my php file below.
PHP
/companies
/**
* #Route("/api/companies", name="api_companies_read")
*/
public function apiCompaniesReadAction(Request $request)
{
$request_body = file_get_contents('php://input');
$json = json_decode($request_body);
//Based on the JSON Payload response adjust the search in the database
if($json){
$page = $json->page;
$pageSize = $json->pageSize;
$skip = $json->skip;
$take = $json->take;
}else{
$page = 1;
$pageSize = 20;
$skip = 1;
$take = 1;
}
$repository = $this->getDoctrine()->getRepository('AppBundle:Company');
/*
findBy(
array $criteria,
array $orderBy = null,
integer|null $limit = null,
integer|null $offset = null
)
*/
$company_total = $repository->findAll();
$company_records = $repository->findBy(array(),array(),$pageSize,($page-1)*$pageSize);
$data["total"] = count($company_total);
foreach($company_records as $company){
$temp["id"] = $company->getId();
$temp["name"] = $company->getName();
$temp["phone"] = $company->getPhone();
$temp["email"] = $company->getEmail();
$data["data"][] = $temp;
}
//converts data to JSON
return new JsonResponse($data);
}
Please remember the above is a Symfony 3.0 php implementation using annotations to set the route. The important part in that code is.
$request_body = file_get_contents('php://input');
$json = json_decode($request_body);
//Based on the JSON Payload response adjust the search in the database
if($json){
$page = $json->page;
$pageSize = $json->pageSize;
$skip = $json->skip;
$take = $json->take;
}else{
$page = 1;
$pageSize = 20;
$skip = 1;
$take = 1;
}
The file_get_contents('php://input'); gets the javascript object that the KendoUI control sends back.
UPDATE # 3 Got Server Sorting Working!
Below is an example implementaiton using Symfony 3.0 and Doctrine to do Server Sorting!
PHP
/**
* #Route("/api/companies", name="api_companies_read")
*/
public function apiCompaniesReadAction(Request $request)
{
$request_body = file_get_contents('php://input');
$json = json_decode($request_body);
//print_r($json);
//default parameters in case of error.
$page = 1;
$pageSize = 20;
$skip = 1;
$take = 1;
$sort = array();
//Based on the JSON Payload response adjust the search in the database
if(isset($json)){
$page = $json->page;
$pageSize = $json->pageSize;
$skip = $json->skip;
$take = $json->take;
if(isset($json->sort)){
//"sort":[{"field":"name","dir":"asc"}]}:
foreach($json->sort as $sortObj){
$sort[$sortObj->field] = $sortObj->dir;
}
}
}
$repository = $this->getDoctrine()->getRepository('AppBundle:Company');
/*
findBy(
array $criteria,
array $orderBy = null,
integer|null $limit = null,
integer|null $offset = null
)
*/
$company_total = $repository->findAll();
$company_records = $repository->findBy(array(),$sort,$pageSize,($page-1)*$pageSize);
$data["total"] = count($company_total);
foreach($company_records as $company){
$temp["id"] = $company->getId();
$temp["name"] = $company->getName();
$temp["phone"] = $company->getPhone();
$temp["email"] = $company->getEmail();
$data["data"][] = $temp;
}
//converts data to JSON
return new JsonResponse($data);
}
That first link is spot on. I had to export data from a grid to pdf and excel adhering to the grid grouping. I finally figured out the semantics. The grid has columns and data objects which you can get through grid calls. The data object holds the grouping information. Here is the processing operation.
In a nutshell, you have to recursively iterate the data object tpo determine the grouping. For each element in the data you need to inspect if the data[x].value exists. If it exists then it is a group object with child data. If it does not exists then you use the normal data[row][column].field to get to the child data. The trick here is to call a recurisive function for each point where dat[0].value has data and finally process the data[row][column] on the unwind.
Below is a js function you can use to inspect the Grid's json dta. I would add a group or two to your grid and see the difference between the data with/without grouping applied and that should be what you need to add to your data....I think you pretty much add data as data={[[],[]]}unless it is a group, then it is data={[value='groupName',{[],[]}]}.
function showData(gridName) {
var grid = $('#' + gridName).data('kendoGrid');
var data = grid.dataSource.data().toJSON();
console.log(data);
}