a suite of UI Components for development of web apps
Advanced User Interface Controls and Components
Created: 26 August 2015
Although you can use some of built-in editors like textbox, combobox, checkbox, etc. to edit cells in AngularJS Grid, in some cases these editors are not enough for specific requirements of your application. To meet these requirements, you may need to create your own custom editor. For this purpose, the best approach is to create an editor template, which can be applied to cells in any column of the Grid directive.
In following sections of this article, you will learn how to create custom editor using a template in AngularJS. This editor will appear as a dropdown list whenever a cell is clicked.
Similar: DropDown List in Tree Grid Cells for Angular 2
In our example, we have a Grid showing information about movies. The 'Genre' column contains information about movie genre, where movie can belong to one or more genres. By default, cells in this column show multiple genres separated by comma. To edit cell value we cannot use the built-in label editor. We cannot use the combo box editor also, because we want to be able to select multiple options, not just one.
The best way is to create a checked list as dropdown editor and applied to each cell in 'Genre' column. This will allow us to check different genres from the list and apply the chosen genres to the selected cell. In order to create this, we will use a template.
At first, we need to create a template using some standard HTML elements. We need a <div> tag that will hold other elements in one block. For a checked list we will use the <ul> and <li> tags where each list element contains a checkbox and label. We also need two buttons, Ok and Cancel, to confirm our selection or cancel the edit process.
angular
.module("appModule", ["integralui"])
.controller("appCtrl", ["$scope", "IntegralUITreeGridService", "$timeout", function($scope, $gridService, $timeout){
$scope.gridName = "gridSample";
$scope.editCell = null;
$scope.genres = [
{ text: "Action", checked: false },
{ text: "Adventure", checked: false },
{ text: "Animation", checked: false },
{ text: "Biography", checked: false },
{ text: "Comedy", checked: false },
{ text: "Crime", checked: false },
{ text: "Drama", checked: false },
{ text: "Fantasy", checked: false },
{ text: "Horror", checked: false },
{ text: "Mystery", checked: false },
{ text: "Sci-Fi", checked: false },
{ text: "Thriller", checked: false },
{ text: "Western", checked: false }
];
}]);
<div ng-app="appModule" ng-controller="appCtrl">
<script type="text/ng-template" id="dropdown-editor.html">
<div class="cell-editor" ng-model="editCell">
<ul class="checked-list">
<li ng-repeat="item in genres">
<iui-checkbox class="check-item" checked="item.checked">{{item.text}}</iui-checkbox>
</li>
</ul>
<div class="editor-panel">
<button class="inline-button" ng-click="onOk(editCell)">Ok</button>
<button class="inline-button" ng-click="onCancel(editCell)">Cancel</button>
</div>
</div>
</script>
</div>
<iui-treegrid name="{{gridName}}" columns="columns" rows="rows" show-footer="false" before-edit="onBeforeEdit(e)" after-edit="onAfterEdit(e)"></iui-treegrid>
/* Editor Template Inline */
.cell-editor
{
background: white;
font-size: 0.75em;
}
.checked-list
{
margin: 0;
overflow: auto;
padding: 1px;
margin: 0;
height: 135px;
}
.checked-list li
{
padding: 0;
margin: 0;
list-style-type: none;
border: thin solid transparent;
}
.checked-list li:hover
{
background: #197EC5;
color: white;
}
.check-item
{
display: inline-block;
margin: 2px;
vertical-align: middle;
}
.iui-checkbox
{
padding: 5px;
}
.iui-checkbox:hover
{
color: white;
}
.editor-panel
{
background: #e5e5e5;
border-top: thin solid gray;
margin: 0;
padding: 5px;
text-align: center;
}
.inline-button
{
background: #2455b0;
border: thin solid transparent;
color: white;
margin: 0 5px;
width: 100px;
height: 25px;
}
.inline-button:hover
{
background-color: #153268;
border: thin solid #0F244A;
}
As you can see, all elements in our template are standard HTML elements. However, you can use any custom element or AngularJS directive to create your own template.
Now, in order to use this template as cell editor, we need to link it with the currently selected cell. We can do this by using the AngularJS ng-model directive. As value we will use the cell that is currently edited, which is retrieved from beforeEdit event. This event is fired just before editing starts and editor is shown, and within the event the cell object is carried:
// beforeEdit event is fired just before dropdown editor is shown and prior editing process starts
$scope.onBeforeEdit = function(e){
if (e.cell){
$scope.editCell = e.cell;
var cellItems = e.cell.value;
if (cellItems){
resetGenres();
for (var i = 0; i < cellItems.length; i++)
cellItems[i].checked = true;
}
showCheckedFirst();
}
}
// After edting is over, reset the editing cell
$scope.onAfterEdit = function(e){
$scope.editCell = null;
}
After editing process is complete and dropdown editor is closed, the afterEdit event is fired. We can handle this event to reset the editing cell.
Next, we need to add handlers for click events from Ok and Cancel buttons. Whenever Ok button is clicked, a list of checked items is created. For each checked option, the name of the genre is added to a string variable.
Because we previously linked our template to the selected cell, we can use this to change the cell value. The value of this variable is then applied to the cell text, while cell value field holds and array of checked options.
// Confirm changes in dropdown editor and apply them to the editing cell
// At the end close the editor
$scope.onOk = function(cell){
if (cell){
var list = [];
for (var i = 0; i < $scope.genres.length; i++){
if ($scope.genres[i].checked)
list.push($scope.genres[i]);
}
cell.text = '';
for (var i = 0; i < list.length; i++)
cell.text += list[i].text + ", ";
if (cell.text != '')
cell.text = cell.text.substring(0, cell.text.length - 2);
cell.value = list;
}
$gridService.closeEditor($scope.gridName, cell);
}
If Cancel button is clicked, the editing is cancelled, and the cell text and value fields remain unchanged. In both functions, the editor is closed by calling the closeEditor method.
Finally, we need to link our editor template to the column by which cells will be edited. In our case this is the column titled 'Genre'.
$scope.columns = [
{ id: 1, headerText: "Title", width: 200 },
{
id: 2,
editorType: 'checkbox',
editorSettings: {
style: {
general: 'checkbox',
box: {
general: 'checkbox-box',
checked: 'checkbox-checked',
indeterminate: 'checkbox-indeterminate',
unchecked: 'checkbox-unchecked'
}
},
threeState: true
},
contentAlignment: 'center',
width: 30,
fixedWidth: true
},
{ id: 3, headerText: "Year", headerAlignment: "center", contentAlignment: "center", width: 70 },
{
id: 4,
headerText: "Genre",
headerAlignment: "center",
contentAlignment: "center",
editorType: 'dropdown',
editorTemplate: "'dropdown-editor.html'",
width: 270
},
{ id: 5, headerText: "Ratings", headerAlignment: "center", contentAlignment: "center", width: 70 },
{ id: 6, headerText: "Released", headerAlignment: "center", contentAlignment: "center", width: 120 }
];
As options, we will create a checked list of all movie genres. This list is organized in a way that at first appear the currently selected genres in alphabetical order, followed by all other genres also sorted in alphabetical order. More details about this are included in downloadable sample (see link below).
As above demonstration shows, whenever a cell from the 'Genre' column is clicked, the dropdown editor will appear. The dropdown list includes all genres as options. We can select multiple genres, by simply clicking on the checkbox or the genre name. All selected genres are then applied to the grid cell by clicking on the Ok button. The result is shown in a cell as comma-separated text.
The complete sample code is available as part of the IntegralUI Studio for Web product package.