製品版のみの機能
ツリー グリッド - 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.1/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" /> <link href="http://cdn-na.infragistics.com/igniteui/2024.1/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.1/latest/js/extensions/infragistics.ui.editors.knockout-extensions.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2024.1/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.1/latest/js/infragistics.core.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2024.1/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; } } }