AngularJS: Editable Grid
An an example of an excel type editable grid using AngularJS for easy Model <=> View binding
HTML
<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<script src="https://raw.github.com/coreyti/showdown/master/compressed/showdown.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<div ng-controller="demo">
<div class="w3-container">
<h4>AngularJS: Editable Grid</h4>
</div>
<div class="w3-container">
<table class="w3-table-all w3-hoverable">
<tr class="w3-blue">
<td>First Name</td>
<td>Last Name</td>
</tr>
<tr ng-repeat="row in rows">
<td valign="right">
<div contentEditable="true" ng-model="row.firstName" ng-click="elementClicked($index)"></div>
</td>
<td valign="right">
<div contentEditable="true" ng-model="row.lastName" ng-click="elementClicked($index)"></div>
</td>
</tr>
</table>
<br/>
<button class="w3-button w3-white w3-border w3-border-blue w3-round-large" ng-click="addRow()">Add Row</button>
</div>
<div class="w3-container">
<h5>Analytics</h5>
<p class="analytics"><b>Row Count:</b> {{ rows.length }}</p>
<p class="analytics"><b>Focused Index:</b> {{ focusedIndex }}</p>
</div>
<div class="w3-container">
<h5>Rows</h5>
<div ng-repeat="row in rows">
<p class="analytics"><b>Row Index:</b> {{$index}} {{ row.firstName }} {{ row.lastName }}</p>
</div>
</div>
</div>
CSS
body{
font-family: Sans-serif;
}
div{
width:250px;
}
div[contentEditable] {
cursor: pointer;
background-color: white;
padding: .2em;
}
div[contentEditable]:focus {
cursor: pointer;
background-color: lightyellow;
padding: .2em;
}
h1{
font-size: x-large;
font-weight: bold;
}
h2{
font-family: Lucida Console;
font-size: larger;
font-weight: 700;
margin-bottom: 5px;
}
h3{
font-family: Lucida Console;
font-size: medium;
font-weight: 500;
margin-bottom: 5px;
}
p {
width: 400px;
}
.analytics{
margin: .3em;
}
.userInputPrompt{
color: gray;
opacity: 0.7;
font-style: italic;
}
JavaScript
//Instantiate the parent angualr module
var myApp = angular.module('myApp', []);
//Define and instantiate the views controller
myApp.controller('demo', ['$scope', function($scope){
//define the default value for a new row
$scope.defaultValue = 'Please Enter a Value';
//define the rows array variable and first row with seed values that are not the enter data cell prompt
$scope.rows = [{firstName:'Michael', lastName:'Griehm'}];
$scope.focusedIndex = null;
//define the add row function to add a row the rows array
$scope.addRow = function() {
$scope.rows.push({firstName: '', lastName: ''});
};
$scope.elementClicked = function($index){
$scope.focusedIndex = $index;
};
}]);
myApp.directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
//element render event handler that applies the value of the controller's view to the element, or add a user input prompt if the value is a blank string
ctrl.$render = function() {
if (ctrl.$viewValue.length === 0){
elm.html(scope.defaultValue);
elm.addClass('userInputPrompt');
}
else{
elm.html(ctrl.$viewValue);
}
};
//element keydown event handler to avoid allowing the enter button to add a new line feed in the cell
elm.bind('keydown', function(event) {
if (event.which === 13) {
event.preventDefault();
}
});
//element keyup event handler to capture the new value of the element and apply it to the view
elm.bind('keyup', function() {
scope.$apply(function() {
ctrl.$setViewValue(elm.html());
});
});
//element focus event handler...