Available in the Full Version
Data Grid - Editing Customization
This sample demonstrates how a custom editor provider could be nested within a custom Row Edit Dialog.
This sample uses CTP (Community Technical Preview) features. The API and behavior may change when these features are released with full support.
This sample is designed for a larger screen size.
On mobile, try rotating your screen, view full size, or email to another device.
The custom editor provider in this sample is implemented in dialogTemplate which is rendered against currently edited record.
This custom provider contains an igUpload control which allows users to upload an image of their own in order to edit the Image column of igGrid.
The dialog used in this sample is a custom widget that utilizes the igSplitter control and replaces the default modal dialog.
The custom modal dialog allows closing and applying the changes via either the on-screen Done and Cancel buttons or the keyboard Enter and ESC keys.
The interaction with the grid is not blocked, and the end user can change the row in edit mode while the dialog is opened.
In order to show the Row Edit Dialog you need to click or tap on a row to pop it up.
Code View
Copy to Clipboard
<!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>
<!-- 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>
</head>
<body>
<style>
.ui-igedit-container {
width: 150px !important;
}
.dialogFooter button {
margin: .5em .4em .5em 0;
cursor: pointer;
}
.ui-igsplitter .ui-icon-close {
font-size: 11px;
}
</style>
<table id="grid1"></table>
<br />
<script id="dialogTemplate" type="text/html">
<div style="float: left; width:50%; margin-left: 15px; margin-top: 15px;" id="templateContainer">
<strong style="margin-left: 5px">${Name}</strong><br /><br />
<table id="dialogTmpTable" style="width: 50%;">
<colgroup>
<col style="width: 30%;" />
<col style="width: 60%;" />
</colgroup>
<tbody data-render-tmpl="true"></tbody>
</table>
<div data-editor-for-imageurl="true"></div>
</div>
</script>
<script id="editorsTemplate" type="text/html">
<tr>
<td><strong>${headerText}</strong></td>
<td><input data-editor-for-${key}="true" /></td>
</tr>
</script>
<script type="text/javascript">
var northwindEmployees = [
{ "ID": 1, "Name": "Davolio, Nancy", "Title": "Sales Representative", "ImageUrl": "/images/samples/nw/employees/1.png", "Phone": "(206) 555-9857", "PhoneUrl": "tel:(206) 555-9857", "BirthDate": "1948-12-08T00:00:00", "HireDate": "1992-05-01T00:00:00", "Country": "USA", "Languages": [{ name: "English" }, { name: "Russian" }] },
{ "ID": 2, "Name": "Fuller, Andrew", "Title": "Vice President, Sales", "ImageUrl": "/images/samples/nw/employees/2.png", "Phone": "(206) 555-9482", "PhoneUrl": "tel:(206) 555-9482", "BirthDate": "1952-02-19T00:00:00", "HireDate": "1992-08-14T00:00:00", "Country": "USA", "Languages": [{ name: "English" }, { name: "German" }] },
{ "ID": 3, "Name": "Leverling, Janet", "Title": "Sales Representative", "ImageUrl": "/images/samples/nw/employees/3.png", "Phone": "(206) 555-3412", "PhoneUrl": "tel:(206) 555-3412", "BirthDate": "1963-08-30T00:00:00Z", "HireDate": "1992-04-01T00:00:00Z", "Country": "USA", "Languages": [{ name: "English" }] },
{ "ID": 4, "Name": "Peacock, Margaret", "Title": "Sales Representative", "ImageUrl": "/images/samples/nw/employees/4.png", "Phone": "(206) 555-8122", "PhoneUrl": "tel:(206) 555-8122", "BirthDate": "1937-09-19T00:00:00Z", "HireDate": "1993-05-03T00:00:00Z", "Country": "USA", "Languages": [{ name: "English" }, { name: "Spanish" }] },
{ "ID": 5, "Name": "Buchanan, Steven", "Title": "Sales Manager", "ImageUrl": "/images/samples/nw/employees/5.png", "Phone": "(71) 555-4848", "PhoneUrl": "tel:(71) 555-4848", "BirthDate": "1955-03-04T00:00:00Z", "HireDate": "1993-10-17T00:00:00Z", "Country": "UK", "Languages": [{ name: "English" }, { name: "Italian" }] },
{ "ID": 6, "Name": "Suyama, Michael", "Title": "Sales Representative", "ImageUrl": "/images/samples/nw/employees/6.png", "Phone": "(71) 555-7773", "PhoneUrl": "tel:(71) 555-7773", "BirthDate": "1963-07-02T00:00:00Z", "HireDate": "1993-10-17T00:00:00Z", "Country": "UK", "Languages": [{ name: "English" }, { name: "Portuguese" }] },
{ "ID": 7, "Name": "King, Robert", "Title": "Sales Representative", "ImageUrl": "/images/samples/nw/employees/7.png", "Phone": "(71) 555-5598", "PhoneUrl": "tel:(71) 555-5598", "BirthDate": "1960-05-29T00:00:00Z", "HireDate": "1994-01-02T00:00:00Z", "Country": "UK", "Languages": [{ name: "English" }, { name: "French" }, { name: "Spanish" }] },
{ "ID": 8, "Name": "Callahan, Laura", "Title": "Inside Sales Coordinator", "ImageUrl": "/images/samples/nw/employees/8.png", "Phone": "(206) 555-1189", "PhoneUrl": "tel:(206) 555-1189", "BirthDate": "1958-01-09T00:00:00Z", "HireDate": "1994-03-05T00:00:00Z", "Country": "USA", "Languages": [{ name: "English" }, { name: "Mandarin" }] },
{ "ID": 9, "Name": "Dodsworth, Anne", "Title": "Sales Representative", "ImageUrl": "/images/samples/nw/employees/9.png", "Phone": "(71) 555-4444", "PhoneUrl": "tel:(71) 555-4444", "BirthDate": "1966-01-27T00:00:00Z", "HireDate": "1994-11-15T00:00:00Z", "Country": "UK", "Languages": [{ name: "English" }, { name: "Japanese" }] }
];
$(function () {
//var currCallbacks;
//creating custom editor provider
$.ig.EditorProviderUpload = $.ig.EditorProvider.extend({
createEditor: function (callbacks, key, editorOptions, tabIndex, format, element) {
this.noImagePath = "../images/samples/grid/noimage.png";
this.currCallbacks = callbacks;
var tmpContainer = $("#templateContainer");
//appending teh div and the image elemnts
tmpContainer.parent().prepend('<div id="container" style="width: 35%;float: left;position:relative; padding-top:5%; margin-top: 32px; margin-left: 20px;"><img id="imgTmp" src="" alt="" title="" width="120px" height="120px"/><div id="tooltip" style="left:25%;width:120px;position:absolute;"></div></div>');
tmpContainer.parent().append('<div style="clear:both;"></div><div id="error-message" style="float: right;color: #FF0000; font-weight: bold;"></div>');
this.createUpload();
this.image = $("#imgTmp");
return element;
},
attachErrorEvents: function (errorShowing, errorShown, errorHidden) { },
getValue: function () {
return this.image.attr("src") || this.noImagePath;
},
setValue: function (val) {
this.image.attr("src", val);
},
createUpload: function () {
// if upload exists - remove it and re-create new upload
var $tooltip = $("#tooltip"), self = this;
$('#upload').remove();
$("<div id='upload'></div>").appendTo($tooltip);
$("#upload").igUpload({
width: "120px",
autostartupload: true,
maxFileSize: 500000,
allowedExtensions: ["jpg", "jpeg", "gif", "png"],
fileSelected: function (e, args) {
args.owner.element.hide();
},
fileUploaded: $.proxy(this.fileUploadedEvt, this),
onError: function (e, args) {
self.showAlert(args);
},
locale: {
labelUploadButton: "Edit",
labelAddButton: "Edit"
},
controlId: "serverID4"
});
},
fileUploadedEvt: function (evt, ui) {
var button = $("#upload_bb"),
upload = $("#upload"),
sMsg = ui.fileInfo.serverMessage,
self = this;
if (!sMsg) {
sMsg = "../images/samples/grid/noimage.png";
this.showAlert({ errorMessage: 'The file cannot be uploaded.' });
} else {
sMsg = 'data:image/png;base64,' + sMsg;
}
$("#imgTmp").attr("src", sMsg);
//callbacks collection
this.currCallbacks.textChanged();
// re-create upload
setTimeout(function () {
self.createUpload();
}, 10);
},
showAlert: function (args) {
var self = this;
$("#error-message").html(args.errorMessage)
.stop(true, true).fadeIn(500).delay(3000).fadeOut(500);
setTimeout(function () {
self.createUpload();
}, 10);
},
destroy: function () {
var $upload = $("#upload");
if ($upload.data('igUpload')) {
$upload.igUpload("destroy");
}
}
});
$.widget("ui.SplitterDialog", $.ui.igGridModalDialog, {
_create: function () {
var d = this.element, self = this, gc, header, footer, $buttonSet, $buttonOK, $buttonCancel, o = this.options, self = this,
outerContianer, closeButton, btnContainer;
// get the grid's container
gc = d.closest(".ui-iggrid");
d.detach();
outerContianer = "<div id='customContainerDiv'></div>";
gc.wrap(outerContianer).wrap("<div></div>");
gc.parent().parent().append(d);
this._customSplitterContainer = $("#customContainerDiv");
this._customSplitterContainer.igSplitter(
{
width: "100%",
height: "400px",
panels: [
{ size: "30%" },
{ size: "70%", collapsible: true }
]
}
);
// adding the header
header = $("<div></div>")
.addClass("ui-widget-header")
.css("padding", "4px")
.text(this.options.locale.modalDialogCaptionText)
.appendTo(d);
//adding close button
btnContainer = $("<div></div>").appendTo(header).addClass("ui-iggrid-modaldialog-caption-buttoncontainer");
closeButton = $("<button type='button'></button>")
.attr("id", "dialog_closeButton")
.appendTo(btnContainer);
closeButton.igButton({
onlyIcons: true,
icons: {
primary: "ui-icon-close"
},
width: "20px",
height: "20px",
click: function () {
self.closeModalDialog(false, true);
}
});
//adding footer
footer = $("<div class='dialogFooter'></div>")
//.addClass(this.css.modalDialogFooter)
.attr("id", this._id("footer"))
.appendTo(d);
$buttonSet = $("<div></div>")
.appendTo(footer);
$buttonOK = $("<button></button>")
.attr("id", this._id("footer_buttonok"))
.appendTo($buttonSet);
$buttonOK.igButton({
labelText: o.locale.buttonApplyText,
title: o.locale.buttonApplyTitle,
disabled: o.buttonApplyDisabled,
click: function () {
self.closeModalDialog(true, true);
}
});
$buttonCancel = $("<button></button>")
.attr("id", this._id("footer_buttoncancel"))
.appendTo($buttonSet);
$buttonCancel.igButton({
labelText: o.locale.buttonCancelText,
title: o.locale.buttonCancelTitle,
click: function () {
self.closeModalDialog(false, true);
}
});
// adding the content
$("<div></div>")
.css({
"overflow": "auto",
"height": gc.outerHeight() - header.outerHeight() - footer.outerHeight()
})
.attr("id", this.element.attr("id") + "_content")
.insertAfter(header);
$buttonSet.css("float", "right");
// dialog css
d.css({
"width": this.options.modalDialogWidth,
"height": gc.outerHeight(),
"background-color": "#FFFFFF"
});
// grid's container need to hide the sliding dialog
gc.css("overflow", "hidden");
gc.find("tbody").on({
mousedown: function (evt) {
var table = gc.find(".ui-iggrid-table"),
rowID = $(evt.target).closest("tr").attr("data-id");
if (table.igGridUpdating("isEditing")) {
if (table.igGridUpdating("endEdit", true)) {
table.igGridUpdating("startEdit", rowID);
}
}
evt.stopPropagation();
},
pointerdown: function (evt) { evt.stopPropagation(); },
touchstart: function (evt) { evt.stopPropagation(); }
}, "td");
d.bind({
// bind to keydown so that the dialog can be closed on ENTER and ESC keypresses,
// also handles the TAB sequence to wrap around the elements of the dialog
keydown: function (e) {
var tabElems, first, last;
if (e.keyCode === $.ui.keyCode.ESCAPE) {
self.closeModalDialog(false, true);
return;
}
if (e.keyCode === $.ui.keyCode.ENTER &&
self.options.closeModalDialogOnEnter &&
!self.options.buttonApplyDisabled) {
self.closeModalDialog(true, true);
return;
}
if (e.keyCode !== $.ui.keyCode.TAB) {
return;
}
tabElems = $(":tabbable", this);
first = tabElems.first();
last = tabElems.last();
if (e.target === last[0] && !e.shiftKey) {
first.focus(1);
return false;
}
if (e.target === first[0] && e.shiftKey) {
last.focus(1);
return false;
}
}
});
},
openModalDialog: function () {
var d = this.element, noCancel;
if (this._modalDialogOpened) {
return;
}
noCancel = this._trigger(
this.events.modalDialogOpening,
null,
{
modalDialog: d, owner: this
}
);
if (noCancel) {
this._modalDialogOpened = true;
d.show();
d.prev().show();
this._customSplitterContainer.igSplitter("setFirstPanelSize", "50%");
this._trigger(
this.events.modalDialogOpened,
null,
{
modalDialogElement: d, owner: this, shouldFocus: true
}
);
}
},
closeModalDialog: function (accepted, fromUI) {
var d = this.element, noCancel = true, self = this;
if (!this._modalDialogOpened) {
return;
}
noCancel = this._trigger(
this.events.modalDialogClosing,
null,
{
modalDialog: d,
owner: this,
accepted: !!accepted,
raiseEvents: fromUI
});
if (noCancel) {
this._modalDialogOpened = false;
d.hide();
d.prev().hide();
this._customSplitterContainer.igSplitter("setFirstPanelSize", "100%");
this._customSplitterContainer.igSplitter("firstPanel").css("width", "100%");
}
}
});
$("#grid1").igGrid({
dataSource: northwindEmployees,
primaryKey: "ID",
width: "100%",
height: "400px",
autoCommit: true,
autoGenerateColumns: false,
columns: [
{ headerText: "Employee ID", key: "ID", dataType: "number", hidden: true },
{ headerText: "Image", key: "ImageUrl", dataType: "object", template: "<img width='100' height='90' src='${ImageUrl}' alt='${Name}' title='${Name}' />" },
{ headerText: "Name", key: "Name", dataType: "string" },
{ headerText: "Title", key: "Title", dataType: "string" },
{ headerText: "Phone", key: "Phone", dataType: "string" },
{ headerText: "HireDate", key: "HireDate", dataType: "date" }
],
features: [
{
name: "Updating",
enableAddRow: true,
enableDeleteRow: false,
editMode: "dialog",
dialogWidget: "SplitterDialog",
columnSettings: [
{
columnKey: "ImageUrl",
readOnly: false,
editorProvider: new $.ig.EditorProviderUpload()
}
],
rowEditDialogOptions: {
dialogTemplateSelector: "#dialogTemplate",
editorsTemplateSelector: "#editorsTemplate",
showReadonlyEditors: false,
editorsColumnWidth: 150
}
}
]
});
});
</script>
</body>
</html>