I am trying to develop kendo grid using Asp.NET MVC and Angularjs. my code is as mentioned below.
Index.cshtml
<div ng-controller="telerikGridController">
<kendo-grid options="mainGridOptions">
<div k-detail-template>
<kendo-tabstrip>
<ul>
<li class="k-state-active">Orders</li>
<li>Contact information</li>
</ul>
<div>
<div kendo-grid k-options="detailGridOptions(dataItem)"></div>
</div>
<div>
<ul>
<li>Country: <input ng-model="dataItem.Country" /></li>
<li>City: <input ng-model="dataItem.City"/></li>
<li>Address: {{dataItem.Address}}</li>
<li>Home phone: {{dataItem.Phone}}</li>
</ul>
</div>
</kendo-tabstrip>
</div>
</kendo-grid>
</div>
AngularJS controller (telerikGridController)
'use strict';
var app = angular.module('myApp', ['kendo.directives', 'ui.bootstrap']);
app.controller('telerikGridController', ['$scope', function telerikGridController($scope) {
$scope.mainGridOptions = {
dataSource: {
type: "json",
transport: {
read: "Grid/Departments"
},
pageSize: 2,
serverPaging: true,
serverSorting: true
},
sortable: true,
pageable: true,
dataBound: function() {
this.expandRow(this.tbody.find("tr.k-master-row").first());
},
columns: [
{
field: "DepartmentName",
title: "Department Name",
width: "120px"
}, {
field: "Country",
title: "Country",
width: "120px"
}, {
field: "City",
width: "120px"
}, {
field: "Phone",
width: "120px"
}, {
field: "Description"
}
]
};
$scope.detailGridOptions = function(dataItem) {
return {
dataSource: {
type: "json",
transport: {
read: "Grid/GetEmployees"
},
serverPaging: true,
serverSorting: true,
serverFiltering: true,
pageSize: 2,
filter: { field: "DeptId", operator: "eq", value: dataItem.DeptId }
},
scrollable: false,
sortable: true,
pageable: true,
filterable:true,
columns: [
{ field: "FirstName", title: "First Name", width: "56px" },
{ field: "LastName", title: "Last Name", width: "110px" },
{ field: "Address", title: "Address" },
{ field: "Phone", title: "Phone", width: "190px" }
]
};
}
}
]);
ASP.NET MVC Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using KendoGridApp.Models;
using Kendo.Mvc;
using Kendo.Mvc.UI;
namespace KendoGridApp.Controllers
{
public class GridController : Controller
{
List<Employee> employees = new List<Employee>();
List<Department> deptList = new List<Department>();
public GridController()
{
Employee employe = new Employee();
employe.FirstName = "First Name";
employe.LastName = "Last Name";
employe.Phone = "+92 302 8888 777";
employe.Address = " Pakistan";
employe.DeptId = 1;
var employe2 = new Employee();
employe2.FirstName = "First Name 2";
employe2.LastName = "Last Name 2";
employe2.Phone = "+92 333 4444 779";
employe2.Address = "UAE";
employe2.DeptId = 2;
var employe3 = new Employee();
employe3.FirstName = "First Name 3";
employe3.LastName = "Last Name 3";
employe3.Phone = "+92 302 4444 779";
employe3.Address = "Sydney,Australia";
employe3.DeptId = 3;
var employe4 = new Employee();
employe4.FirstName = "First Name 4";
employe4.LastName = "Last Name 4";
employe4.Phone = "+92 302 4444 999";
employe4.Address = "Sydney, Australia";
employe4.DeptId = 4;
var employe5 = new Employee();
employe5.FirstName = "First Name 5";
employe5.LastName = "Last Name 5";
employe5.Phone = "+92 302 1111 779";
employe5.Address = "Dubai, UAE";
employe5.DeptId = 5;
var employe6 = new Employee();
employe6.FirstName = "First Name 6";
employe6.LastName = "Last Name 6";
employe6.Phone = "+92 302 0000 779";
employe6.Address = "Dehli, India";
employe6.DeptId = 6;
employees.Add(employe);
employees.Add(employe2);
employees.Add(employe3);
employees.Add(employe4);
employees.Add(employe5);
employees.Add(employe6);
}
// GET: Grid
public ActionResult Index()
{
return View();
}
[HttpGet]
public JsonResult GetEmployees(DataSourceRequest command)
{
int deptId = Convert.ToInt16(Request.Params["filter[filters][0][value]"]);
employees = employees.Where(x => x.DeptId == deptId).ToList();
return Json(employees, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public JsonResult Departments()
{
Department dept = new Department();
dept.DeptId = 1;
dept.DepartmentName = "Information Technology";
dept.Phone = "+1 111 111 111";
dept.Country = "Pakistan";
dept.City = "Lahore";
dept.Description = "This is Description Text 1";
Department dept2 = new Department();
dept2.DeptId = 2;
dept2.DepartmentName = "Mechnical Engineering";
dept2.Phone = "+1 222 111 111";
dept2.Country = "India";
dept2.City = "Dehli";
dept2.Description = "This is Description Text 2";
Department dept3 = new Department();
dept3.DeptId = 3;
dept3.DepartmentName = "Civil Engineering";
dept3.Phone = "+1 111 000 111";
dept3.Country = "Pakistan";
dept3.City = "Islamabad";
dept3.Description = "This is Description Text 3";
Department dept4 = new Department();
dept4.DeptId = 4;
dept4.DepartmentName = "Radiology";
dept4.Phone = "+1 111 222 000";
dept4.Country = "UAE";
dept4.City = "Dubai";
dept4.Description = "This is Description Text 4";
Department dept5 = new Department();
dept5.DeptId = 5;
dept5.DepartmentName = "Defence";
dept5.Phone = "+1 555 888 999";
dept5.Country = "Australia";
dept5.City = "Sydney";
dept5.Description = "This is Description Text 5";
Department dept6 = new Department();
dept6.DeptId = 6;
dept6.DepartmentName = "Socialogy";
dept6.Phone = "+1 555 777 000";
dept6.Country = "United States";
dept6.City = "New York";
dept6.Description = "This is Description Text 6";
deptList.Add(dept);
deptList.Add(dept2);
deptList.Add(dept3);
deptList.Add(dept4);
deptList.Add(dept5);
deptList.Add(dept6);
return Json(deptList, JsonRequestBehavior.AllowGet);
}
}
}
Issue:
Issue i am facing is in GetEmployees JsonResult function, DataSourceRequest command has always Filters = null. Whereas, my request is showing requests like,
Query String Parameters:
take:2
skip:0
page:1
pageSize:2
filter[logic]:and
filter[filters][0][field]:DeptId
filter[filters][0][operator]:eq
filter[filters][0][value]:3
and Request link is like,
GetEmployees?take=2&skip=0&page=1&pageSize=2&filter%5Blogic%5D=and&filter%5Bfilters%5D%5B0%5D%5Bfield%5D=DeptId&filter%5Bfilters%5D%5B0%5D%5Boperator%5D=eq&filter%5Bfilters%5D%5B0%5D%5Bvalue%5D=3
currently I am able to get filters in server side using HttpRequestWrapper as mentioned below in GetEmployees JsonResult
int deptId = Convert.ToInt16(Request.Params["filter[filters][0][value]"]);
but is there any better approach to get these filters at server side? for example using DataSourceRequest?
Thanks.
This is works for me for server side filtering. Try add [DataSourceRequest] tag before variable type to solve your filter binding issue and to handle filtering you can use extension ToDataSourceResult() which provided by Kendo.Mvc.Extensions.
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
// removed for brevity
// .......
return Json(viewModels.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
Hope this help.
Use type: "aspnetmvc-ajax", instead of type: "json", in your dataSource and use the [DataSourceRequest] attribute in your controller.
public JsonResult GetEmployees([DataSourceRequest]DataSourceRequest command)
Finally, After hammering my head long i found the solution.
In my Code above mentioned,
Replace in $scope.detailGridOptions: (telerikGridController)
dataSource: {
type: "json",
transport: {
read: "Grid/GetEmployees"
},
pageSize: 2,
serverPaging: true,
serverSorting: true
},
With:
dataSource: {
type: "aspnetmvc-ajax",
transport: {
read: "Grid/GetEmployees",
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8"
},
schema:
{
data: "Data",
total: "Total",
errors: "Errors"
},
pageSize: 2,
serverPaging: true,
serverSorting: true
},
And in Asp.NET MVC controller:
Replace
[HttpGet]
public JsonResult GetEmployees(DataSourceRequest command)
With
[HttpPost]
public JsonResult GetEmployees(DataSourceRequest command)
And Everything will start working file. you will be receiving Filters/Sort etc everyting in DataSourceRequest object.
Related
In one of my application, have seen browser gets hanging and crashing because of binding 500 000 records in the Kendo Ui-grid.
The grid contains total 20 columns and all the data return from webapi via angular in kendo grid.
it's working fine for 3 columns, when changed to 15 columns it gets a problem for above 100k records.
So I need to test how much columns and records can be hold on kendo grid. I have found there is some options available in kendo called as virtualisation to load the bulk records.
Demo Site is: http://dojo.telerik.com/#sahir/OSeRo
So in the people js have the data, I have tried to add two more columns inside that file I am getting object object in the column.
The problem occurs above 100k record binding without pagination in kendo grid. I have attached a demo project screenshot below for testing the grid.
The code is below:
<!DOCTYPE html>
<html>
<head>
<base href="">
<style>html { font-size: 14px; font-family: Arial, Helvetica, sans-serif; }</style>
<title></title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.1.118/styles/kendo.common-material.min.css" />
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.1.118/styles/kendo.material.min.css" />
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2017.1.118/styles/kendo.material.mobile.min.css" />
<script src="https://kendo.cdn.telerik.com/2017.1.118/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2017.1.118/js/kendo.all.min.js"></script>
<script src="people.js" ></script>
</head>
<body>
<!--<script src="../content/shared/js/people.js"></script>-->
<div id="example">
<div id="message" class="box wide"></div>
<div id="grid"></div>
<script>
$(function() {
var count = 500000;
if (kendo.support.browser.msie) {
if (kendo.support.browser.version < 10) {
count = 100000;
} else {
count = 200000;
}
}
$("#message").text(kendo.format("Generating {0} items", count));
generatePeople(count, function(data) {
var initStart;
var renderStart;
$("#message").text("");
setTimeout(function() {
initStart = new Date();
$("#grid").kendoGrid({
dataSource: {
data: data,
pageSize: 20
},
height: 543,
scrollable: {
virtual: true
},
pageable: {
numeric: false,
previousNext: false,
messages: {
display: "Showing {2} data items"
}
},
columns: [
{ field: "Id", title: "ID", width: "110px" },
{ field: "FirstName", title: "First Name", width: "130px" },
{ field: "LastName", title: "Last Name", width: "130px" },
{ field: "City", title: "City", width: "130px" },
{ field: "CashId", title: "Cash ID", width: "130px" },
{ field: "Title" },
{ field: "productName"},
]
});
initEnd = new Date();
$("#message").text(kendo.format("Kendo UI Grid bound to {0} items in {1} milliseconds", count, initEnd - initStart));
});
});
});
</script>
</div>
</body>
</html>
custom people.js
var firstNames = ["Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne", "Nige"],
lastNames = ["Davolio", "Fuller", "Leverling", "Peacock", "Buchanan", "Suyama", "King", "Callahan", "Dodsworth", "White"],
cities = ["Seattle", "Tacoma", "Kirkland", "Redmond", "London", "Philadelphia", "New York", "Seattle", "London", "Boston"],
titles = ["Accountant", "Vice President, Sales", "Sales Representative", "Technical Support", "Sales Manager", "Web Designer",
"Software Developer", "Inside Sales Coordinator", "Chief Techical Officer", "Chief Execute Officer"],
productNames =["Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne", "Nige"]
birthDates = [new Date("1948/12/08"), new Date("1952/02/19"), new Date("1963/08/30"), new Date("1937/09/19"), new Date("1955/03/04"), new Date("1963/07/02"), new Date("1960/05/29"), new Date("1958/01/09"), new Date("1966/01/27"), new Date("1966/03/27")],
cashId= ["Accountant", "Vice President, Sales", "Sales Representative", "Technical Support", "Sales Manager", "Web Designer",
"Software Developer", "Inside Sales Coordinator", "Chief Techical Officer", "Chief Execute Officer"];
function createRandomData(count) {
var data = [],
now = new Date();
for (var i = 0; i < count; i++) {
var firstName = firstNames[Math.floor(Math.random() * firstNames.length)],
lastName = lastNames[Math.floor(Math.random() * lastNames.length)],
city = cities[Math.floor(Math.random() * cities.length)],
title = titles[Math.floor(Math.random() * titles.length)],
birthDate = birthDates[Math.floor(Math.random() * birthDates.length)],
CashId = cashId[Math.floor(Math.random() * cashId.length)],
age = now.getFullYear() - birthDate.getFullYear(),
productName = productNames[Math.floor(Math.random() * productNames.length)];
data.push({
Id: i + 1,
FirstName: firstName,
LastName: lastName,
City: city,
Title: title,
BirthDate: birthDate,
CashId:cashId,
Age: age,
productName:productNames
});
}
console.log(data);
return data;
}
function generatePeople(itemCount, callback) {
var data = [],
delay = 25,
interval = 500,
starttime;
var now = new Date();
setTimeout(function() {
starttime = +new Date();
do {
var firstName = firstNames[Math.floor(Math.random() * firstNames.length)],
lastName = lastNames[Math.floor(Math.random() * lastNames.length)],
city = cities[Math.floor(Math.random() * cities.length)],
title = titles[Math.floor(Math.random() * titles.length)],
birthDate = birthDates[Math.floor(Math.random() * birthDates.length)],
CashId= cashId[Math.floor(Math.random() * cashId.length)],
age = now.getFullYear() - birthDate.getFullYear(),
productName = productNames[Math.floor(Math.random() * productNames.length)];
data.push({
Id: data.length + 1,
FirstName: firstName,
LastName: lastName,
City: city,
Title: title,
BirthDate: birthDate,
CashId:cashId,
Age: age,
productName:productNames
});
} while(data.length < itemCount && +new Date() - starttime < interval);
if (data.length < itemCount) {
setTimeout(arguments.callee, delay);
} else {
callback(data);
}
}, delay);
}
Update people.js on line 68 (cashId to CashId) and 70 (productNames to productName)
data.push({
Id: data.length + 1,
FirstName: firstName,
LastName: lastName,
City: city,
Title: title,
BirthDate: birthDate,
CashId:CashId,
Age: age,
productName:productName
});
Im using ng-google-chart to create charts from data I receive from a database. I store the data in a table. I need to export both the table and the chart.
I'm using the following technique to export tables (where "exportable" is the div the contains the table):
$scope.export = function ()
{
var blob = new Blob([document.getElementById('exportable').innerHTML], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
});
saveAs(blob, "Record.xls");
alert("export done");
};
I cannot find any way to add the chart to this file.
This is the code to generate a chart
var chart1 = {};
chart1.type = "ColumnChart";
chart1.cssStyle = "height:400px; width:500px;";
chart1.data = {
"cols": [
{ id: "gender", label: "Gender", type: "string" },
{ id: "number", label: "number", type: "number" }
], "rows": [
{
c: [
{ v: "male" },
{ v: $scope.male, f: $scope.male }
]
},
{
c: [
{ v: "female" },
{ v: $scope.female }
]
}
]
};
chart1.options = {
"title": "",
"isStacked": "true",
"fill": 20,
"displayExactValues": true,
"vAxis": {
"title": "Number", "gridlines": { "count": 6 }
},
"hAxis": {
"title": "gender"
}
};
chart1.formatters = {};
$scope.chart = chart1;
}
To getImageURI of the chart, wait for the ready event and call the function.
Then you can add the image somewhere on the page.
You can even hide the original chart if needed...
Following is an example of loading the image URI into another element.
google.load('visualization', '1', {packages:['corechart'], callback: drawChart});
function drawChart() {
var data = google.visualization.arrayToDataTable([
["Element", "Density", { role: "style" } ],
["Copper", 8.94, "#b87333"],
["Silver", 10.49, "silver"],
["Gold", 19.30, "gold"],
["Platinum", 21.45, "color: #e5e4e2"]
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2]);
var options = {
title: "Density of Precious Metals, in g/cm^3",
width: 600,
height: 400,
bar: {groupWidth: "95%"},
legend: { position: "none" },
};
var chart = new google.visualization.ColumnChart(document.getElementById("chart_div"));
google.visualization.events.addListener(chart, 'ready', function () {
document.getElementById("chart_image").insertAdjacentHTML('beforeEnd', '<img alt="Chart Image" src="' + chart.getImageURI() + '">');
});
chart.draw(view, options);
}
<script src="https://www.google.com/jsapi"></script>
<span>CHART</span>
<div id="chart_div"></div>
<br/>
<span>IMAGE</span>
<div id="chart_image"></div>
I have a grid, inside of some column of which I have created a combobox editing UI, using columns.editor function.
My goal is every time a user selects some value from the combobox -while populating a newly created grid record-, this value to be
removed from the list options of a next record's combobox.
One of the things i've tried is shown below:
function equipmentDropDownEditor(container, options) {
var equipmentComboBox = $('<input id="equipmentDropDownEditor" required data-text-field="name" data-value-field="name" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: equipmentTypesDS,
dataBound: function(e) {
var equipmentData = e.sender.dataSource.data();
if(currentlyInsertedEquipmentTypes.length > 0){
for(var i=0;i<currentlyInsertedEquipmentTypes.length;i++){
$.each( equipmentData, function( index, selectedEquipmentData ) {
if (selectedEquipmentData.name == currentlyInsertedEquipmentTypes[i]){
var dataItem = e.sender.dataSource.at(index);
console.log("dataItem: " + dataItem.name + " is being removed");
e.sender.dataSource.remove(dataItem);
}
});
}
}
}
});
}
I've created a global array variable named "currentlyInsertedEquipmentTypes" inside of which I hold all the user's already selected values
(for example if the user has created 2 records inside the grid and has selected "laptop" option in the combobox of the first and "workstation" option
in the combobox of the second --> currentlyInsertedEquipmentTypes = ["laptop", "workstation"] ).
Inside the combobox dataBound event I check whether the user has already selected values (currentlyInsertedEquipmentTypes.length>0)
and if he has, I locate the corresponding object inside the bound dataSource and I remove it, so that it wont be available in the next record's combobox list.
This is where the whole thing crashes even though the data item removal takes place.
Am i missing something that i should do after the data item removal? Should i rebind the datasource to the combobox in some way?
Any help would be much appreciated.
[EDIT]
---- The combobox datasource code
var equipmentTypesDS= new kendo.data.DataSource({
transport: {
read: {
url: "api/equipment_types",
type: "GET",
data: {
//"equipment_category": 1
},
dataType: "json"
}
},
schema: {
data: "data",
total: "total"
}
});
--- the kendo grid code:
$("#popup_equipment").kendoGrid({
dataSource: {
schema:{
model:{
id: "equipment_type_id",
fields:{
equipment_type_id: { editable: false },
name: { }, //validation: {required: true}, defaultValue: "LAPTOP",
items:{ type: "number", defaultValue:1, validation: { required: true, min: 1} }
}
}
}
},
toolbar: ["create"],
columns: [
{ field: "name", title: "εξοπλισμός", width: "300px", editor: equipmentDropDownEditor, template: "#=name#" },
{ field: "items", title:"πλήθος", width: "80px"},
{ command: ["destroy"], title: " ", width: "100px" }
],
//editable: "inline",//true,
editable:{confirmation: false},
scrollable: false,
selectable: false
});
[EDIT 2]
$("#popup_equipment").kendoGrid({
dataSource: {
schema:{
model:{
id: "equipment_type_id",
fields:{
equipment_type_id: { editable: false },
name: { }, //validation: {required: true}, defaultValue: "LAPTOP",
items:{ type: "number", defaultValue:1, validation: { required: true, min: 1} }
}
}
}
},
toolbar: ["create"],
columns: [
{ field: "name", title: "εξοπλισμός", width: "60%", editor: equipmentDropDownEditor, template: "#=name#" },
{ field: "items", title:"πλήθος", width: "20%"},
{ command: ["destroy"], title: " ", width: "20%" }
],
editable:{confirmation: false},
scrollable: false,
selectable: false,
save: function(e){
console.log("GRID SAVE EVENT! ", e);
var equipment_name = e.values.name;
equipmentTypesDS.get(equipment_name).used = true;
console.log("equipmentTypesDS", equipmentTypesDS);
console.log("END OF GRID SAVE EVENT!");
}
});
function equipmentDropDownEditor(container, options) {
var equipmentComboBox = $('<input id="equipmentDropDownEditor" required data-text-field="name" data-value-field="name" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: equipmentTypesDS,
});
}
var equipmentTypesDS= new kendo.data.DataSource({
transport: {
read: {
url: "api/equipment_types",
type: "GET",
data: {
//"equipment_category": 1
},
dataType: "json"
}
},
schema: {
data: "data",
total: "total",
model:{
id: "name"
}
},
filter: { field: "used", operator: "neq", value: true }
});
I would suggest a different approach. Instead of removing the element filter it out.
Example: I define a DataSource with a list of Cities (your Inserted Equipment) as follow:
var cityDS = new kendo.data.DataSource ({
data : [
{ City : "Seattle", used : false },
{ City : "Tacoma", used : false },
{ City : "Kirkland", used : false },
{ City : "Redmond", used : false },
{ City : "London", used : false },
{ City : "Philadelphia", used : false },
{ City : "New York", used : false },
{ City : "Boston", used : false }
],
schema : {
model : {
id : "City"
}
},
filter: { field: "used", operator: "eq", value: false }
});
As you can see I added a field called used that simply says if that City is already used or not. And I set it as id of this DataSource. In addition, I set a filter saying that I only want those where used id equal (eq) to false.
The editor function is pretty much yours:
function cityDropDownEditor(container, options) {
var equipmentComboBox = $('<input required data-text-field="City" data-value-field="City" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: cityDS
});
}
but with no dataBound or any other event handler.
Finally in the Grid when I save a record, I filter that city from the list. Something like:
var grid = $("#grid").kendoGrid({
dataSource: ds,
editable : "popup",
pageable : true,
toolbar: [ "create" ],
columns :
[
{ field: "FirstName", width: 90, title: "First Name" },
{ field: "LastName", width: 200, title: "Last Name" },
{ field: "City", width: 200, editor : cityDropDownEditor }
],
save : function(e) {
console.log("e", e);
var city = e.model.City;
cityDS.get(city).used = true;
}
}).data("kendoGrid");
This might work if you start the Grid with no elements otherwise you would have to conveniently initialize the used field. It might require some additional code dealing with cases as changing the City but from your description, doesn't seem to be the case.
You can see this running here : http://jsfiddle.net/OnaBai/ZH4aD/
I have a grid and use rowactions grouping plugin to have an action button in the grouping header. The fist visible column in the grid is a checkbox column. I need to make the checkboxes in the same group behave the same way. 1) if a user checks one of the checkboxes, all boxes in the same group has to be checked. 2) Also I need to look at another field in the same row and if it doesn't have a value, disable checkboxes (all in the same group), otherwise all checkboxes should be enabled.
I also tried xtype:checkbox. For #1 I just cannot figure out how to get the siblings. I tried using the checkchange - I could get a record there - but I don't know how to get other records from the same group. For #2 - how do I get the record - I need to check one of the values and set the ckeckbox enabled/disabled.
Any ideas?
Thank you.
EDIT: for #2 I went with disable checkcolumn for some rows answer here
This is my index.cshtml
<script type="text/javascript">
Ext.require([
'Ext.container.Viewport',
'Ext.grid.*',
'Ext.util.*',
'Ext.Date.*',
'Ext.ux.CheckColumn',
'ACTGRID.ui.GroupPanelGrid'
]);
Ext.onReady(function () {
initialize();
});
function initialize() {
Ext.Ajax.timeout = 60000; // 60 seconds
var myGrid = Ext.create('ACTGRID.ui.GroupPanelGrid');
var viewport = Ext.create('Ext.container.Viewport', {
layout: 'border',
items: [{
region: 'center',
title: 'Grid',
items: myGrid }]
});
};
</script>
This is the GroupPanelGrid.js:
Ext.Date.patterns = {
ISO8601Long: "Y-m-d H:i:s",
ISO8601Short: "Y-m-d",
ShortDate: "n/j/Y",
LongDate: "l, F d, Y",
FullDateTime: "l, F d, Y g:i:s A",
MonthDay: "F d",
ShortTime: "g:i A",
LongTime: "g:i:s A",
SortableDateTime: "Y-m-d\\TH:i:s",
UniversalSortableDateTime: "Y-m-d H:i:sO",
YearMonth: "F, Y"
};
Ext.define('ACTGRID.ui.TransactionsLateModel', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Id', type: 'int' },
{ name: 'Approval', type: 'boolean' },
{ name: 'ErrorComment', type: 'string' },
{ name: 'ErrorSource', type: 'string'},
{ name: 'RecordDate', type: 'date', dateFormat: 'MS' }],
idProperty: 'Id'
});
Ext.define("ACTGRID.ui.GroupPanelGrid", {
extend: "Ext.grid.Panel",
requires: ['ACTGRID.ui.TransactionsLateModel',
'Ext.ux.grid.RowActions',
'Ext.grid.feature.Grouping'],
initComponent: function () {
var me = this;
me.features = [Ext.create('Ext.grid.feature.Grouping', {
groupHeaderTpl: 'Grouping Header: {name} ({rows.length}
Item{[values.rows.length > 1 ? "s" : ""]})',
enableGroupingMenu: false })];
me.columns = me.buildColumns();
me.store = Ext.create('Ext.data.Store', {
model: 'ACTGRID.ui.TransactionsLateModel',
remoteSort: true,
storeId: 'TransactionsLateStoreId',
autoLoad: true,
buffered: true,
autoSync: true,
groupField: 'RecordDate',
pageSize: 70,
proxy: {
type: 'rest',
timeout: 600000,
url: '/Home/ActionsGrid/',
reader: {
type: 'json',
root: 'transaction',
totalProperty: "Total"
},
writer: {
type: 'json',
root: 'transaction'
}
}
});
me.autoSizeColumns = true;
me.autoScroll = true;
me.forcefit = true;
me.callParent(arguments);
},
buildColumns: function () {
var me = this;
return [
{
xtype: 'rowactions', hidden: true, hideable: false,
actions: [{}],
keepSelection: true,
groupActions: [{
iconCls: 'icon-grid',
qtip: 'Action on Group',
align: 'left',
callback: function (grid, records, action, groupValue) {
var rec = [].concat(records);
/*does something unrelated*/
}
}]
},
{
text: 'Approval', dataIndex: 'Approval', sortable: true,
width: 50,
xtype: 'checkcolumn',
listeners: {
checkchange: function (column, recordIndex, checked) {
var record = me.getStore().data.items[recordIndex].data;
/* Do something here? - How do I get all the siblings */
},
beforerender: function (e, eOpts) {
/* How do I check another cell in this row to see if it has a value
And disable the ckeckbox and set it read only? */
}
}
},
{ text:'ErrorComment', dataIndex: 'ErrorComment' },
{ text:'ErrorSource', dataIndex: 'ErrorSource'},
{ text:'RecordDate', dataIndex: 'RecordDate', renderer: Ext.util.Format.dateRenderer (Ext.Date.patterns.ShortDate)}];
},
height: 600,
width: 'auto'
});
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
[AcceptVerbs(HttpVerbs.Get)]
[ActionName("ActionsGrid")]
public ActionResult GetActionsGrid()
{
DetailsViewModel model = new DetailsViewModel();
List<ExtJsTreeGrid.Models.ActionGrid> ActionsFromDB = model.GetActionsGrid();
model.transaction = ActionsFromDB;
model.success = true;
return Json(model, JsonRequestBehavior.AllowGet);
}
[AcceptVerbs(HttpVerbs.Put)]
[ActionName("ActionsGrid")]
public ActionResult SetActionsGrid()
{
// do something
}
}
Model:
public class ActionGrid
{
public Int32 Id { get; set; }
public bool Approval { get; set; }
public string ErrorComment { get; set; }
public string ErrorSource { get; set; }
public DateTime RecordDate { get; set; }
}
public class DetailsViewModel
{
public List<ActionGrid> transaction = new List<ActionGrid>();
public bool success = true;
public List<ActionGrid> GetActionsGrid()
{
return new List<ActionGrid> {
new ActionGrid { Id = 1,
Approval = true,
ErrorComment = "Comment",
ErrorSource = string.Empty,
RecordDate = new DateTime(1979, 11, 23)
},
new ActionGrid { Id = 5,
Approval = true,
ErrorComment = "Comment",
ErrorSource = "brodas",
RecordDate = new DateTime(1979, 11, 23)
},
new ActionGrid { Id = 6,
Approval = true,
ErrorComment = "Comment",
ErrorSource = string.Empty,
RecordDate = new DateTime(1979, 11, 23)
},
new ActionGrid { Id = 7,
Approval = true,
ErrorComment = string.Empty,
ErrorSource = "brodas",
RecordDate = new DateTime(1979, 11, 23)
},
new ActionGrid { Id = 2,
Approval = true,
ErrorComment = string.Empty,
ErrorSource = string.Empty,
RecordDate = new DateTime(1980, 05, 20)
},
new ActionGrid { Id = 3,
Approval = true,
ErrorComment = "Comment",
ErrorSource = "brodas",
RecordDate = new DateTime(1995, 01, 12)
},
new ActionGrid { Id = 4,
Approval = true,
ErrorComment = string.Empty,
ErrorSource = string.Empty,
RecordDate = new DateTime(2010, 09, 02)
},
new ActionGrid { Id = 8,
Approval = true,
ErrorComment = string.Empty,
ErrorSource = "brodas",
RecordDate = new DateTime(2010, 09, 02)
},
new ActionGrid { Id = 9,
Approval = true,
ErrorComment = "Comment Errors",
ErrorSource = string.Empty,
RecordDate = new DateTime(2010, 09, 02)
},
new ActionGrid { Id = 10,
Approval = true,
ErrorComment = "Comment Errors",
ErrorSource = "brodas",
RecordDate = new DateTime(2010, 09, 02)
},
new ActionGrid { Id = 11,
Approval = true,
ErrorComment = string.Empty,
ErrorSource = "brodas",
RecordDate = new DateTime(2010, 09, 02)
}};
}
For requirement #1, the checkchange listener is indeed the right place to implement it.
To get all the records in the group, you need to grab a reference to the grid's store, and then use its query method, with your grouping field, and the value in the checked record.
Here's an example:
checkchange: function(col, index, checked) {
var grid = col.up('tablepanel'),
store = grid.getStore(),
record = store.getAt(index),
group = record.get('group'),
// returns a MixedCollection (not a simple array)
groupRecords = store.query('group', group);
// apply the same check status to all the group
groupRecords.each(function(record) {
record.set('checked', checked);
});
}
For your second requirement, I don't really understand when you want it to happen.
Anyway, the check column doesn't support disabling at the row level, so you'll have to implement that first.
The simplest way to do that is to add a field to your model to hold the disabled state. Let's call it 'disabled'. Then, you need two things.
First, render the checkbox disabled state. For that, let's override the renderer of the check column:
,renderer: function(value, meta) {
// Adding disabled class according to record's checkable
// field
if (meta.record.get('disabled')) {
meta.tdCls += ' ' + this.disabledCls;
}
// calling the overridden method (cannot use callParent
// since we haven't define a new class)
return Ext.grid.column.CheckColumn.prototype.renderer.apply(this, arguments);
}
Next, we need to prevent checking or unchecking disabled records. That can be done in the beforecheckchange event:
,beforecheckchange: function(col, index) {
var grid = col.up('tablepanel'),
store = grid.getStore(),
record = store.getAt(index);
if (record.get('disabled')) {
return false;
}
}
Now, you can just enable/disable a record's checkbox by setting the record's 'disabled' field.
record.set('disabled', true); // enable
record.set('disabled', false); // disable
Complete Example
Here's a complete example that implements your first requirement and, maybe, your second one. If that not what you meant for the second requirement, that should take you almost there...
The example can be seen running in this fiddle.
Ext.widget('grid', {
renderTo: Ext.getBody()
,height: 300
,features: [{ftype: 'grouping'}]
,store: {
proxy: {type: 'memory', reader: 'array'}
,fields: [
'name', // something to see
'group', // grouping field
'checkable', // for req #2
'checked', // for check column
'disabled' // for disabled state
]
,groupField: 'group'
,data: [
['Foo 1', 'foo', true],
['Foo 2', 'foo', false],
['Foo 3', 'foo', true],
['Bar 1', 'bar', false],
['Bar 2', 'bar', true],
['Baz 1', 'baz', false],
['Baz 2', 'baz', false],
['Baz 3', 'baz', true]
]
}
,columns: [{
xtype: 'checkcolumn'
,width: 50
,dataIndex: 'checked'
,listeners: {
checkchange: function(col, index, checked) {
var grid = col.up('tablepanel'),
store = grid.getStore(),
record = store.getAt(index),
group = record.get('group'),
// returns a MixedCollection (not a simple array)
groupRecords = store.query('group', group),
// for req #2
disableGroup = !record.get('checkable');
groupRecords.each(function(record) {
record.set('checked', checked);
// Here's how to disable the group... If that's
// really what you want.
record.set('disabled', disableGroup);
});
}
// Returning false from this listener will prevent the
// check change. This is used to implement disabled
// checkboxes.
,beforecheckchange: function(col, index) {
var grid = col.up('tablepanel'),
store = grid.getStore(),
record = store.getAt(index);
if (record.get('disabled')) {
return false;
}
}
}
,renderer: function(value, meta) {
// Adding disabled class according to record's checkable
// field
if (meta.record.get('disabled')) {
meta.tdCls += ' ' + this.disabledCls;
}
// calling the overridden method (cannot use callParent
// since we haven't define a new class)
return Ext.grid.column.CheckColumn.prototype.renderer.apply(this, arguments);
}
},{
dataIndex: 'name'
,text: "Name"
,flex: 1
},{
dataIndex: 'checkable'
,text: "Checkable"
}]
});
as for my case, i have a separate checkbox outside my gridpanel which controls the selection of the checkcolumn.
//Avoid view update after each row
grid.store.suspendEvents();
grid.store.each(function(rec) {
rec.set('ctrl_select_flag', ctrl.value);
});
grid.store.resumeEvents();
grid.getView().refresh();
ctrl.value refers to the component which controls my checkcolumn selection. ctrl_select_flag refers to the dataIndex of my checkcolumn.
Have you ever make a checkbox column in Handsontable?
I try to use every way to do it, but it's not working.
When user click checkbox on header, all row in column was be checked.
Thanks for any help.
You can create a checkbox column by simply setting the column type option to 'checkbox'.
var $container = $("#example1");
$container.handsontable({
data: data,
startRows: 5,
colHeaders: true,
minSpareRows: 1,
columns: [
{data: "id", type: 'text'},
//'text' is default, you don't actually have to declare it
{data: "isActive", type: 'checkbox'},
{data: "date", type: 'date'},
{data: "color",
type: 'autocomplete',
source: ["yellow", "red", "orange", "green", "blue", "gray", "black", "white"]
}
]
});
For more detail see this example
HTML:
<div id="example2" class="handsontable"></div>
Javascript:
var myData = [{
name: "Marcin",
active: true
}, {
name: "Jude",
active: false
}, {
name: "Zylbert",
active: false
}, {
name: "Henry",
active: false
}]
var $container = $("#example2");
$container.handsontable({
data: myData,
rowHeaders: true,
columns: [{
data: 'name'
}, {
type: 'checkbox',
data: 'active'
}],
colHeaders: function (col) {
switch (col) {
case 0:
return "<b>Bold</b> and <em>Beautiful</em>";
case 1:
var txt = "<input type='checkbox' class='checker' ";
txt += isChecked() ? 'checked="checked"' : '';
txt += "> Select all";
return txt;
}
}
});
$container.on('mouseup', 'input.checker', function (event) {
var current = !$('input.checker').is(':checked'); //returns boolean
for (var i = 0, ilen = myData.length; i < ilen; i++) {
myData[i].active = current;
}
$container.handsontable('render');
});
function isChecked() {
for (var i = 0, ilen = myData.length; i < ilen; i++) {
if (!myData[i].active) {
return false;
}
}
return true;
}
Here's the example you're looking for
http://jsfiddle.net/yr2up2w5/
Hope this helps you.
There's now a checkbox tutorial in the Handsontable documentation.