Slick Grid Grouping:
Design Page:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GanttChart.aspx.cs" Inherits="WebProject.GanttChart" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Gantt Chart</title>
<link rel="stylesheet" href="Scripts/slick.grid.css" type="text/css"/>
<link rel="stylesheet" href="Scripts/jquery-ui-1.8.16.custom.css" type="text/css"/>
<link rel="stylesheet" href="Scripts/examples.css" type="text/css"/>
<style>
.cell-title {
font-weight: bold;
}
.cell-effort-driven {
text-align: center;
}
.toggle {
height: 9px;
width: 9px;
display: inline-block;
}
.toggle.expand {
background: url(/images/expand.gif) no-repeat center center;
}
.toggle.collapse {
background: url(/images/collapse.gif) no-repeat center center;
}
#contextMenu {
background: #e1efc7;
border: 1px solid gray;
padding: 2px;
display: inline-block;
min-width: 100px;
-moz-box-shadow: 2px 2px 2px silver;
-webkit-box-shadow: 2px 2px 2px silver;
z-index: 99999;
}
#contextMenu li {
padding: 4px 4px 4px 14px;
list-style: none;
cursor: pointer;
background: url("../images/arrow_right_peppermint.png") no-repeat center left;
}
#contextMenu li:hover {
background-color: white;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<table width="100%">
<tr>
<td valign="top" width="50%">
<div id="myGrid" style="width:600px;height:500px;"></div>
</td>
</tr>
</table>
</div>
</form>
<ul id="contextMenu" style="display:none;position:absolute">
<b>Set:</b>
<li data="indent">Indent</li>
<li data="outdent">Outdent</li>
<li data="new">New</li>
<li data="delete">Delete</li>
</ul>
</body>
</html>
<script src="Scripts/firebugx.js"></script>
<script src="Scripts/jquery-1.7.min.js"></script>
<script src="Scripts/jquery-ui-1.8.16.custom.min.js"></script>
<script src="Scripts/jquery.event.drag-2.0.min.js"></script>
<script src="Scripts/slick.core.js"></script>
<script src="Scripts/slick.formatters.js"></script>
<script src="Scripts/slick.editors.js"></script>
<script src="Scripts/slick.rowselectionmodel.js"></script>
<script src="Scripts/slick.grid.js"></script>
<script src="Scripts/slick.dataview.js"></script>
<script src="Scripts/slick.pager.js"></script>
<script src="Scripts/slick.columnpicker.js"></script>
<script src="Scripts/GanttChart.js"></script>
.cs File
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
namespace WebProject
{
public partial class GanttChart : System.Web.UI.Page
{
string sqlconnection = System.Configuration.ConfigurationManager.ConnectionStrings["connectionString"].ToString();
protected void Page_Load(object sender, EventArgs e)
{
Ajax.Utility.RegisterTypeForAjax(typeof(GanttChart));
}
[Ajax.AjaxMethod(Ajax.HttpSessionStateRequirement.Read)]
public DataTable Getdata()
{
try
{
SqlConnection con = new SqlConnection(sqlconnection);
SqlCommand cmd = new SqlCommand("select Title,CONVERT( NVARCHAR(125),Start,106)[Start],CONVERT( NVARCHAR(125),[End],106)[End],DATEDIFF(dd,Start,[End]) Duration , 0 [indent] from Gnatt", con);
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sd.Fill(dt);
return dt;
}
catch (Exception)
{
throw;
}
}
}
}
.js File:
var Browser = {
Title: 0,
Duration: 1,
PerctComplete: 2,
Start: 3,
Finish: 4,
EffortDriven: 5
}
var dataView;
var grid;
var data = [];
function requiredFieldValidator(value) {
if (value == null || value == undefined || !value.length) {
return { valid: false, msg: "This is a required field" };
} else {
return { valid: true, msg: null };
}
}
var TaskNameFormatter = function (row, cell, value, columnDef, dataContext) {
value = value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
var spacer = "<span style='display:inline-block;height:1px;width:" + (15 * dataContext["indent"]) + "px'></span>";
var idx = dataView.getIdxById(dataContext.id);
if (data[idx + 1] && data[idx + 1].indent > data[idx].indent) {
if (dataContext._collapsed) {
return spacer + " <span class='toggle expand'></span> " + value;
} else {
return spacer + " <span class='toggle collapse'></span> " + value;
}
} else {
return spacer + " <span class='toggle'></span> " + value;
}
};
var columns = [
{ id: "title", name: "Title", field: "title", width: 220, cssClass: "cell-title", formatter: TaskNameFormatter, editor: Slick.Editors.Text, validator: requiredFieldValidator },
{ id: "duration", name: "Duration", field: "duration", editor: Slick.Editors.Text },
{ id: "%", name: "% Complete", field: "percentComplete", width: 80, resizable: false, formatter: Slick.Formatters.PercentCompleteBar, editor: Slick.Editors.PercentComplete },
{ id: "start", name: "Start", field: "start", minWidth: 60, editor: Slick.Editors.Date },
{ id: "finish", name: "Finish", field: "finish", minWidth: 60, editor: Slick.Editors.Date },
{ id: "effort-driven", name: "Effort Driven", width: 80, minWidth: 20, maxWidth: 80, cssClass: "cell-effort-driven", field: "effortDriven", formatter: Slick.Formatters.Checkmark, editor: Slick.Editors.Checkbox, cannotTriggerInsert: true }
];
var options = {
editable: true,
enableAddRow: true,
enableCellNavigation: true,
asyncEditorLoading: false
};
function DateDiff(date1, date2) {
//date1 = date1.split("/").reverse().join("-");
//date2 = date2.split("/").reverse().join("-");
var datediff = new Date(date2) - new Date(date1);
return (datediff / (24 * 60 * 60 * 1000));
}
$(document).ready(function () {
populateData();
});
function populateData() {
var indent = 0;
var parents = [];
var dataTable = GanttChart.Getdata();
console.log(dataTable.value);
if (dataTable.value != null) {
if (dataTable.value.Rows.length == 0) {
showerrormsg("No Record Found ");
return false;
}
for (var i = 0; i < dataTable.value.Rows.length; i++) {
var d = (data[i] = {});
d['id'] = i + 1;
d["indent"] = dataTable.value.Rows[i].indent;
d["title"] = dataTable.value.Rows[i].Title;
d["start"] = dataTable.value.Rows[i].Start;
d["finish"] = dataTable.value.Rows[i].End;
d["start_temp"] = dataTable.value.Rows[i].Start;
d["finish_temp"] = dataTable.value.Rows[i].End;
d["ParentIndent"] = 0;
d["ChildofIndent"] = 0;
d["duration"] = dataTable.value.Rows[i].Duration;
}
}
//else
// AddNewLine();
BindGrid(columns, data);
};
function BindGrid(_columns, _data) {
dataView = new Slick.Data.DataView({ inlineFilters: true });
grid = new Slick.Grid("#myGrid", dataView, _columns, options);
grid.setSelectionModel(new Slick.RowSelectionModel());
grid.render();
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
grid.onContextMenu.subscribe(function (e) {
e.preventDefault();
var cell = grid.getCellFromEvent(e);
$("#contextMenu")
.data("row", cell.row)
.css("top", e.pageY)
.css("left", e.pageX)
.show();
$("body").one("click", function () {
$("#contextMenu").hide();
});
});
grid.onCellChange.subscribe(function (e, args) {
if (args.cell == Browser.Finish) {
data[args.row]["duration"] = DateDiff(data[args.row]["start"], data[args.row]["finish"]);
grid.invalidateRow(args.row);
grid.render();
}
});
grid.onClick.subscribe(function (e, args) {
if ($(e.target).hasClass("toggle")) {
var item = dataView.getItem(args.row);
if (item) {
if (!item._collapsed) {
item._collapsed = true;
} else {
item._collapsed = false;
}
dataView.updateItem(item.id, item);
}
e.stopImmediatePropagation();
}
});
dataView.beginUpdate();
dataView.setItems(_data);
dataView.endUpdate();
}
$("#contextMenu").click(function (e) {
if (!$(e.target).is("li")) {
return;
}
if (!grid.getEditorLock().commitCurrentEdit()) {
return;
}
var row = $(this).data("row");
// data[row].priority = $(e.target).attr("data");
if ($(e.target).attr("data") == 'indent')
{
AddIndent(row);
ShowCollapse(row);
grid.updateRow(row);
}
else if ($(e.target).attr("data") == 'outdent') {
OutIndent(row);
ShowCollapse(row);
grid.updateRow(row);
}
else if ($(e.target).attr("data") == 'new') {
AddNewLine(row+1);
}
else if ($(e.target).attr("data") == 'delete') {
DeleteRow(row);
}
});
function ShowCollapse(RowID) {
var item = dataView.getItem(RowID);
if (!item._collapsed) {
item._collapsed = true;
} else {
item._collapsed = false;
}
if (RowID > 0) {
grid.gotoCell(RowID - 1, 0, true);
grid.gotoCell(RowID, 0, true);
}
}
function AddIndent(RowID)
{
if (RowID > 0) {
// for (var i = RowID; i > 0; i--) {
UpdateValues(RowID);
// }
}
}
function UpdateValues(RowID)
{
var Previndent = data[RowID - 1].indent;
var PrevRow = RowID - 1;
var CurrentRowID=0;
if (Previndent - data[RowID].indent >= 0 ) {
data[RowID].indent = data[RowID].indent + 1;
if (data[PrevRow].ParentIndent == 0 && data[RowID].indent > data[PrevRow].indent) {
data[RowID].ParentIndent = data[RowID].ParentIndent + 1;
data[RowID].ChildofIndent = data[RowID].ChildofIndent + 1;
ParentRowID = PrevRow;
}
else {
data[RowID].ParentIndent = data[RowID].ParentIndent + 1;
data[RowID].ChildofIndent = data[RowID].ChildofIndent + 1;
}
if (data[RowID].ChildofIndent != data[PrevRow].ChildofIndent) {
data[PrevRow].start = data[RowID].start;
data[PrevRow].finish = data[RowID].finish;
data[PrevRow].duration = data[RowID].duration;
}
//else {
// for (var i = PrevRow; i >= 0; i--) {
// if (data[i].ParentIndent > 0) {
// data[RowID].ChildofIndent = data[i].ParentIndent;
// ParentRowID = i;
// }
// }
//}
grid.updateRow(PrevRow);
grid.render();
if (data[RowID].ChildofIndent == data[PrevRow].ChildofIndent && data[PrevRow].ParentIndent >= data[RowID].ParentIndent)
UpdateparentDates(ParentRowID, RowID);
}
}
function UpdateparentDates(PrevRow, RowID) {
var minDate;
var maxDate;
var CurrentRowID = 0;
var ParentIndentValue = data[RowID].ParentIndent;
for (var i = RowID; i <= 7 ; i++) {
if (i == RowID) {
minDate = data[PrevRow].start;
maxDate = data[PrevRow].finish;
}
if (data[i].ChildofIndent == ParentIndentValue) {
if (minDate > data[RowID].start)
minDate = data[RowID].start;
if (maxDate < data[RowID].finish)
maxDate = data[RowID].finish;
data[PrevRow].start = minDate;
data[PrevRow].finish = maxDate;
data[PrevRow].duration = DateDiff(minDate, maxDate);
}
}
grid.updateRow(PrevRow);
grid.render();
}
function OutIndent(RowID)
{
if (data[RowID].indent > 0) {
var PrevRow = RowID - 1;
data[RowID].indent = data[RowID].indent - 1;
data[PrevRow].start = data[PrevRow].start_temp;
data[PrevRow].finish = data[PrevRow].finish_temp;
data[PrevRow].duration = DateDiff(data[PrevRow]["start_temp"], data[PrevRow]["finish_temp"]);
grid.updateRow(PrevRow);
grid.render();
}
}
function AddNewLine(RowID) {
var _item = {
"indent": 0, "id": 1000 + dataView.getLength(), "title": "New Task", "duration": ""
};
data.splice(RowID, 0, _item);
dataView.setItems(data);
grid.invalidateRows();
grid.updateRowCount();
grid.render();
}
function DeleteRow(RowID) {
var current_row = RowID;
data.splice(current_row, 1);
var r = current_row;
while (r < data.length) {
grid.invalidateRow(r);
r++;
}
dataView.setItems(data);
grid.updateRowCount();
grid.render();
}
OUTPUT: