製品版のみの機能
ツリー グリッド - KnockoutJS のバインド
このサンプルでは、10,000 以上のレコードのリモート読み込み、KnockoutJS バインディングを使用したグリッド行の編集を紹介します。
このサンプルは CTP 機能を使用しています。製品版では、API や動作が変更される場合があります。
このサンプルは、より大きい画面サイズのためにデザインされました。
モバイル デバイスで画面を回転、フル サイズ表示、またはその他のデバイスにメールで送信します。
社員の写真および名前を表示するには、ページング ブレッドクラムでカスタム関数を使用します。ツリー グリッドで有効なその他の機能は、選択とリモート ページングです。社員データの保存はローカル データ ソースのみで実行され、サーバーに変更が保存されないことに注意してください。
コード ビュー
クリップボードへコピー
@using Infragistics.Web.Mvc
@using IgniteUI.SamplesBrowser.Models.Northwind
@using System.Data
<!DOCTYPE html>
<html>
<head>
<title></title>
<!-- Ignite UI for jQuery Required Combined CSS Files -->
<link href="http://cdn-na.infragistics.com/igniteui/2024.2/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" />
<link href="http://cdn-na.infragistics.com/igniteui/2024.2/latest/css/structure/infragistics.css" rel="stylesheet" />
<script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script>
<script src="http://jp.igniteui.com/js/external/knockout-latest.js"></script>
<script src="http://jp.igniteui.com/js/external/knockout.mapping-latest.js"></script>
<script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/extensions/infragistics.ui.editors.knockout-extensions.js"></script>
<script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/extensions/infragistics.ui.combo.knockout-extensions.js"></script>
<!-- Ignite UI for jQuery Required Combined JavaScript Files -->
<script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/infragistics.core.js"></script>
<script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/infragistics.lob.js"></script>
<script src="http://jp.igniteui.com/data-files/org-chart-available-positions.js"></script>
<style type="text/css">
#sampleContainer fieldset {
margin:0;
}
#editForm .ui-dialog-title{
text-transform:uppercase;
}
.employee-table {
width:100%;
overflow:hidden;
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
margin-bottom:10px;
padding-bottom:6px;
padding-top:20px;
}
.employee-data {
float:left;
width:80%;
}
.employee-pic {
float:right;
width:20%;
}
.form-row {
width:100%;
overflow:hidden;
margin-bottom:14px;
}
#sampleContainer fieldset .row-edit-dialog-container-head {
font-size:16px;
}
#sampleContainer fieldset .row-edit-dialog-container-head label {
display: inline !important;
}
.row-edit-dialog-container-head #idEditor {
line-height:32px;
display:inline;
}
.form-row label {
float:left;
margin:0 10px 0 0 !important;
line-height:32px;
width:30%;
text-align: right;
}
.emp-pic {
width: 50px;
height: 50px;
border-radius: 25px;
-webkit-border-radius: 25px;
-moz-border-radius: 25px;
display: inline-block;
}
.emp-pic-big {
width: 100px;
height: 100px;
border-radius: 50px;
-webkit-border-radius: 50px;
-moz-border-radius: 50px;
float:right;
}
.emp-pic-breadcrumb {
margin-right: 5px;
float: left;
width: 16px;
height: 16px;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
}
.breadcrumb-label {
margin-right: 5px;
float: left;
}
.breadcrumb-container {
display: inline-block;
}
#orgChartGrid_container {
float: left;
}
#org-chart-edit {
float: left;
}
#org-chart-edit.label {
display: block;
margin-top: 5px;
}
.ui-dialog-buttonset {
float: right;
}
.ui-dialog .ui-dialog-titlebar {
padding:0.7em 1em;
}
.ui-dialog .ui-dialog-titlebar.ui-state-focus, .ui-dialog.ui-igdialog {
border-color:#888 !important;
}
</style>
</head>
<body>
<script type="text/javascript">
var contextRowFunc = function (dataRow, $textArea, parents, mode) {
var contextRowText = "<div class=\"breadcrumb-container\">";
// Default text when there are no parents
if (!parents || parents.length == 1) {
contextRowText += "組織図";
}
else {
$(parents).slice(0, -1).each(function (index) {
contextRowText += "<div class=\"emp-pic-breadcrumb\" style=\"background: url(" + this.row["Picture"].replace(/50/g, "16") + ") no-repeat;\"></div><div class=\"breadcrumb-label\">" + this.row["FirstName"] + " " + this.row["LastName"] + " > </div>";
});
}
contextRowText += "</div>";
return contextRowText;
}
function formatReportsTo(val, record) {
var manager = ko.utils.arrayFirst(orgChartVM.directors(), function (item) {
return item.EmployeeID() === record.ReportsTo;
});
if (manager) {
return manager.FullName();
}
else {
return '';
}
}
var Employee = function (EmployeeID, FirstName, LastName, ReportsTo, Picture, Position, HireDate, AnnualSalary) {
var self = this;
self.EmployeeID = ko.observable(EmployeeID);
self.FirstName = ko.observable(FirstName);
self.LastName = ko.observable(LastName);
self.ReportsTo = ko.observableArray([ReportsTo]);
self.Picture = ko.observable(Picture);
self.BigPicture = self.Picture() ? self.Picture().replace(/50/g, "100") : '';
self.Position = ko.observableArray([Position]);
self.HireDate = ko.observable(HireDate);
self.AnnualSalary = ko.observable(AnnualSalary);
self.FullName = ko.computed(function () {
return self.FirstName() + ' ' + self.LastName();
});
}
function EmployeesViewModel() {
var self = this;
self.selectedEmployee = ko.observable();
self.employeeSelectionChanged = function (evt, ui) {
if (!ui.row) { return; }
var employee = $("#orgChartGrid").igTreeGrid("findRecordByKey", ui.row.id);
self.selectedEmployee(new Employee(
employee.EmployeeID,
employee.FirstName,
employee.LastName,
employee.ReportsTo,
employee.Picture,
employee.Position,
employee.HireDate,
employee.AnnualSalary));
$('#editForm').igDialog("open");
};
self.availablePositions = orgChartAvailablePositions;
self.directors = ko.observableArray();
$.get('@Url.Action("GetDirectors")', function (data) {
$(data).each(function () {
self.directors.push(new Employee(this.EmployeeID, this.FirstName, this.LastName, null, null, null, null, null));
});
});
self.save = function () {
var empRecord = $("#orgChartGrid").igTreeGrid("findRecordByKey", self.selectedEmployee().EmployeeID());
empRecord.FirstName = self.selectedEmployee().FirstName();
empRecord.LastName = self.selectedEmployee().LastName();
empRecord.ReportsTo = self.selectedEmployee().ReportsTo()[0];
empRecord.Picture = self.selectedEmployee().Picture();
empRecord.Position = self.selectedEmployee().Position()[0];
empRecord.HireDate = self.selectedEmployee().HireDate();
empRecord.AnnualSalary = self.selectedEmployee().AnnualSalary();
$("#orgChartGrid").igTreeGrid("commit");
$("#editForm").igDialog("close");
};
self.cancel = function () {
$("#editForm").igDialog("close");
};
}
orgChartVM = new EmployeesViewModel();
$(function () {
ko.applyBindings(orgChartVM);
$("#editForm").igDialog({
headerText: "社員を編集",
state: "closed",
modal: true,
draggable: false,
resizable: false,
height: "460px",
width: "600px"
});
});
</script>
@(Html.Infragistics().TreeGrid<IgniteUI.SamplesBrowser.Models.OrgChartEmployee>()
.ID("orgChartGrid")
.Width("815px")
.Height("600px")
.DataSourceUrl(Url.Action("editing-knockout"))
.AutoGenerateColumns(false)
.PrimaryKey("EmployeeID")
.ChildDataKey("Subs")
.Columns(c =>
{
c.For(x => x.EmployeeID).HeaderText("従業員 ID").DataType("number").Hidden(true);
c.For(x => x.Picture).HeaderText("写真").DataType("string").Width("100px").Template("<div class=\"emp-pic\" style=\"background: url(${Picture}) no-repeat;\"></div>");
c.For(x => x.FirstName).HeaderText("名前").DataType("string").Template("${FirstName} ${LastName}");
c.For(x => x.Position).HeaderText("位置").DataType("string");
c.For(x => x.HireDate).HeaderText("雇用日").DataType("date").Format("yyyy-MM-dd");
c.For(x => x.AnnualSalary).HeaderText("給与").DataType("number").Format("currency");
c.For(x => x.ReportsTo).Hidden(true);
c.For(x => x.LastName).HeaderText("上司").DataType("string").FormatterFunction("formatReportsTo");
})
.DefaultColumnWidth("100px")
.InitialExpandDepth(0)
.InitialIndentationLevel(2)
.RenderExpansionIndicatorColumn(true)
.Features(f =>
{
f.Selection()
.Mode(SelectionMode.Row)
.ClientEvents(new Dictionary<string, string>() {
{ GridSelectionClientEvents.RowSelectionChanged, "orgChartVM.employeeSelectionChanged(evt,ui);" }
});
f.Paging()
.Type(OpType.Remote)
.Mode(TreeGridPagingMode.AllLevels)
.ContextRowMode(TreeGridPagingContextRowMode.Breadcrumb)
.RenderContextRowFunc("contextRowFunc")
.PageSize(100);
})
.Render()
)
<div id="editForm">
<fieldset class="org-chart-edit" data-bind="visible: selectedEmployee(), with: selectedEmployee">
<div class="row-edit-dialog-container-head">
<label for="idEditor">従業員 ID:</label>
<div id="idEditor" data-bind="text: EmployeeID"></div>
</div>
<div class="employee-table">
<div class="employee-data">
<div class="form-row">
<label for="firstNameEditor">名前:</label>
<input id="firstNameEditor" type="text" data-bind="igTextEditor: { value: FirstName, selectionOnFocus: 'atEnd' }" />
</div>
<div class="form-row">
<label for="lastNameEditor">名字:</label>
<input id="lastNameEditor" type="text" data-bind="igTextEditor: { value: LastName, selectionOnFocus: 'atEnd' }" />
</div>
<div class="form-row">
<label for="positionEditor">位置:</label>
<select id="positionEditor" data-bind="igCombo: { dataSource: $root.availablePositions, selectedItems: Position, enableClearButton: false, mode: 'dropdown' }"></select>
</div>
<div class="form-row">
<label for="hireDateEditor">雇用日:</label>
<input id="hireDateEditor" data-bind="igDateEditor: { value: HireDate }" />
</div>
<div class="form-row">
<label for="reportsToEditor">上司:</label>
<select id="reportsToEditor" data-bind="igCombo: { dataSource: $root.directors, valueKey: 'EmployeeID', textKey: 'FullName', selectedItems: ReportsTo, placeHolder: '上司を選択' }"></select>
</div>
<div class="form-row">
<label for="annualSalaryEditor">給与:</label>
<input id="annualSalaryEditor" type="number" step="10" data-bind="igCurrencyEditor: { value: AnnualSalary, selectionOnFocus: 'atStart' }" />
</div>
</div>
<div class="employee-pic">
<div class="emp-pic-big" data-bind="style: { background: 'url(\'' + BigPicture + '\') no-repeat' }"></div>
</div>
</div>
<div class="ui-dialog-buttonset">
<button class="ui-button-text-only ui-button ui-igbutton ui-widget ui-widget-content ui-corner-all ui-state-default" data-bind="click: $root.save"><span id="grid_updating_dialog_container_footer_buttonok_lbl" class="ui-button-text">社員を保存</span></button>
<button class="ui-button-text-only ui-button ui-igbutton ui-widget ui-widget-content ui-corner-all ui-state-default" data-bind="click: $root.cancel"><span id="grid_updating_dialog_container_footer_buttoncancel_lbl" class="ui-button-text">キャンセル</span></button>
</div>
</fieldset>
</div>
</body>
</html>
using IgniteUI.SamplesBrowser.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Infragistics.Web.Mvc;
using IgniteUI.SamplesBrowser.Models.Repositories;
using IgniteUI.SamplesBrowser.Models.Northwind;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Text;
namespace IgniteUI.SamplesBrowser.Controllers
{
public class TreeGridController : Controller
{
//
// GET: /TreeGrid/
[ActionName("aspnet-mvc-helper")]
public ActionResult AspMvcHelper()
{
var files = new List<FileExplorer>();
files.Add(new FileExplorer
{
ID = "1",
Name = "Documents",
DateModified = new DateTime(2013, 9, 12),
Type = "File Folder",
Size = 4480,
Files = new List<FileExplorer> {
new FileExplorer { ID = "4", Name = "To do list.txt", DateModified = new DateTime(2013,11,30), Type = "TXT File", Size = 4448 },
new FileExplorer { ID = "5", Name = "To do list.txt", DateModified = new DateTime(11/30/2013), Type = "TXT File", Size = 4448 }
}
});
files.Add(new FileExplorer
{
ID = "2",
Name = "Music",
DateModified = new DateTime(2014, 6, 10),
Type = "File Folder",
Size = 5594,
Files = new List<FileExplorer> {
new FileExplorer { ID = "6", Name = "AC/DC", DateModified =new DateTime(2014,6,10), Type = "File Folder", Size = 2726 ,
Files = new List<FileExplorer> {
new FileExplorer { ID = "8", Name = "Stand Up.mp3", DateModified = new DateTime(2014,6,10), Type = "MP3 File", Size = 456 },
new FileExplorer { ID = "9", Name = "T.N.T.mp3", DateModified = new DateTime(2014,6,10), Type = "MP3 File", Size = 1155 },
new FileExplorer { ID = "10", Name = "The Jack.mp3", DateModified = new DateTime(2014,6,10), Type = "MP3 File", Size = 1115 }
}
},
new FileExplorer { ID = "7", Name = "WhiteSnake", DateModified = new DateTime(2014,6,11), Type = "File Folder", Size = 2868,
Files = new List<FileExplorer> {
new FileExplorer { ID = "11", Name = "Trouble.mp3", DateModified = new DateTime(2014,6,11), Type = "MP3 File", Size = 1234 },
new FileExplorer { ID = "12", Name = "Bad Boys.mp3", DateModified = new DateTime(2014,6,11), Type = "MP3 File", Size = 522 },
new FileExplorer { ID = "13", Name = "Is This Love.mp3", DateModified = new DateTime(2014,6,11), Type = "MP3 File", Size = 1112 }
}
}
}
});
files.Add(new FileExplorer
{
ID = "3",
Name = "Pictures",
DateModified = new DateTime(2014, 1, 20),
Type = "File Folder",
Size = 1825,
Files = new List<FileExplorer> {
new FileExplorer { ID = "14", Name = "Jack's Birthday", DateModified = new DateTime(2014,6,21), Type = "File Folder", Size = 631,
Files = new List<FileExplorer> {
new FileExplorer { ID = "16", Name = "Picture1.png", DateModified = new DateTime(2014,6,21), Type = "PNG image", Size = 493 },
new FileExplorer { ID = "17", Name = "Picture2.png", DateModified = new DateTime(2014,6,21), Type = "PNG image", Size = 88 },
new FileExplorer { ID = "18", Name = "Picture3.gif", DateModified = new DateTime(2014,6,21), Type = "GIF File", Size = 50 }
}
},
new FileExplorer { ID = "15", Name = "Trip to London", DateModified = new DateTime(2014,3,11), Type = "File Folder", Size = 1194,
Files = new List<FileExplorer> {
new FileExplorer { ID = "19", Name = "Picture1.png", DateModified = new DateTime(2014,3,11), Type = "PNG image", Size = 974 },
new FileExplorer { ID = "20", Name = "Picture2.png", DateModified = new DateTime(2014,3,11), Type = "PNG image", Size = 142 },
new FileExplorer { ID = "21", Name = "Picture3.png", DateModified = new DateTime(2014,3,11), Type = "PNG image", Size = 41 },
new FileExplorer { ID = "22", Name = "Picture4.png", DateModified = new DateTime(2014,3,11), Type = "PNG image", Size = 25 },
new FileExplorer { ID = "23", Name = "Picture5.png", DateModified = new DateTime(2014,3,11), Type = "PNG image", Size = 12 }
}
}
}
});
return View("aspnet-mvc-helper", files.AsQueryable());
}
[ActionName("load-on-demand")]
public ActionResult LoadOnDemand()
{
return View();
}
[ActionName("remote-features")]
public ActionResult RemoteFeatures()
{
return View();
}
[ActionName("updating")]
public ActionResult Updating()
{
return View();
}
[ActionName("editing-knockout")]
[TreeGridDataSourceAction]
public ActionResult EditingKnockout()
{
var employees = OrgChartEmployeesRepository.GetEmployees();
return View(employees.AsQueryable());
}
public JsonResult GetDirectors()
{
var directors = OrgChartEmployeesRepository.GetDirectors();
return Json(directors, JsonRequestBehavior.AllowGet);
}
#region Data
[TreeGridDataSourceAction]
public ActionResult ChildEmployeesOnDemand()
{
IQueryable allData = RepositoryFactory.GetHierarchicalEmployeeData().AsQueryable();
return View("load-on-demand", allData);
}
[TreeGridDataSourceAction]
public ActionResult GetTreeData()
{
IQueryable allData = RepositoryFactory.GetHierarchicalEmployeeData().AsQueryable();
return View("remote-features", allData);
}
[TreeGridDataSourceAction]
public ActionResult GetTreeGridData()
{
IQueryable allData = RepositoryFactory.GetTreeGridRepository().Get().AsQueryable();
return View("updating", allData);
}
#endregion //Data
public ActionResult EmployeeSaveData()
{
TreeGridModel treeGridModel = new TreeGridModel();
List<Transaction<EmployeeData>> transactions = treeGridModel.LoadTransactions<EmployeeData>(HttpContext.Request.Form["ig_transactions"]);
var employees = RepositoryFactory.GetTreeGridRepository();
foreach (Transaction<EmployeeData> t in transactions)
{
if (t.type == "newrow")
{
employees.Add(t.row);
}
else if (t.type == "deleterow")
{
employees.Delete(o => o.ID == Int32.Parse(t.rowId));
}
else if (t.type == "row")
{
var employee = FindElementEmployees(employees.Get(), Int32.Parse(t.rowId));
if (t.row.FirstName != null)
{
employee.FirstName = t.row.FirstName;
}
if (t.row.LastName != null)
{
employee.LastName = t.row.LastName;
}
if (t.row.Title != null)
{
employee.Title = t.row.Title;
}
if (t.row.Email != null)
{
employee.Email = t.row.Email;
}
if (t.row.HireDate != null)
{
employee.HireDate = t.row.HireDate;
}
employees.Update(employee, o => o.ID == Int32.Parse(t.rowId));
}
else if (t.type == "insertnode")
{
var parentEmployee = FindElementEmployees(employees.Get(), Int32.Parse(t.parentRowId));
if (parentEmployee.Employees == null)
{
parentEmployee.Employees = new List<EmployeeData>() as IEnumerable<EmployeeData>;
}
var temp = parentEmployee.Employees.ToList();
temp.Add(t.row);
parentEmployee.Employees = temp as IEnumerable<EmployeeData>;
}
}
employees.Save();
JsonResult result = new JsonResult();
Dictionary<string, bool> response = new Dictionary<string, bool>();
response.Add("Success", true);
result.Data = response;
return result;
}
private EmployeeData FindElementEmployees(IEnumerable<EmployeeData> data, int id)
{
EmployeeData employee = null;
for (int i = 0; i < data.Count(); i++)
{
if (employee != null)
{
break;
}
employee = GetNode(data.ElementAt(i), id);
}
return employee;
}
public static EmployeeData GetNode(EmployeeData parent, int id)
{
if (parent != null)
{
if (parent.ID.Equals(id))
{
return parent;
}
}
if (parent.Employees != null)
foreach (var child in parent.Employees)
{
if (child.ID.Equals(id))
{
return child;
}
var employee = GetNode(child, id);
if (employee != null)
{
return employee;
}
}
return null;
}
}
}