<html ng-app="userapp">
<head>
<title>Angular + DataTable Demo</title>
<meta name="description" content="Angular Table demo" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.10/angular.min.js"></script>
<link href="//datatables.net/download/build/nightly/jquery.dataTables.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="//datatables.net/download/build/nightly/jquery.dataTables.js"></script>
<script src="https://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.3.0.js"></script>
<!--
Lets assume angular user-link's are reused in many places,
not just in tables.
-->
<script id="userLinkTemplate" type="text/ng-template">
<a href="http://server/edit?user={{user.ID}}">Edit</a>
</script>
<!--
Unfortunately, I can't use the angular template inside tables, so I need to
duplicate the display logic e.g. for user links. ( I could have gone with simple
old-style string concatenation, but prefer Handlebars instead. )
By coincidence, the angular and Handlebar templates are exactly identical
but the handlebar ones are way, way less powerful,
and duplication is needed in the general case, which is so sad! :-(
-->
<script id="userLinkHandlebarTemplate" type="text/x-handlebars-template">
<a href="http://server/edit?user={{user.ID}}">Edit</a>
</script>
</head>
<body ng-controller="TableDemoCtrl" ng-cloak>
<p><i>See comment at top of JavaScript file for description</i></p>
<p>
<!--
The magic of AngularJS for me is that this "just works"
The angular table is automatically updated
-->
<button ng-click="addUserCB()">Add User</button>
</p>
<!-- First a DataTable table and then a raw Angular table -->
<h2>DataTable</h2>
<table id="dataTable">
<thead>
<tr>
<th>Edit</th>
<th>Name</th>
<th>Position</th>
</tr>
</thead>
<!-- DataTable: code to add all tbody data/rows in javascript -->
</table>
<h2>Angular Table</h2>
<table id="angular-has-no-need-for-an-id">
<thead>
<tr>
<th>Edit</th>
<th>Name</th>
<th>Position</th>
</tr>
</thead>
<!-- Angular: code to add all tbody data/rows right here -->
<tbody>
<tr ng-repeat="user in users" user="user">
<td>
<div user-link="user"></div>
</td>
<td>{{user.name}}</td>
<td>{{user.position}}</td>
</tr>
</tbody>
</table>
<!-- See how all the logic for this is right here -->
<p ng-show="users.length">
Here is a link for the first user: <span user-link="users[0]"></span>
</p>
</body>
</html>
/*
Here we show a Datatables+Handlebars table and
a raw AngularJS table.
We'll pretend we want to show some users (from /ajax/objects.txt)
With AngularJS, the javascript is reduced to bindings and glue only.
In the Angular parts of this example, *all* actual view logic
- how the users are displayed -
is in the HTML section, none of it here. Here we *only* deal with model
data
The dataTable is updated by "watching" a variable for changes,
and when it changes,
dataTable.clear().rows.add(data).draw()
The logic that generates data knows view specific things,
such as the columns in the table and which templates to use where.
Most importantly, I can't use any of the Angular functionality inside
my table, creating a non-Angular island in my application, where I need
to duplicate the angular functionality I already have implemented.
(See the HTML file / "pane" for more comments)
The same data is used in both tables:
We get /ajax/objects.txt that has 57 employees.
Lets use them as a pool of employees, pretend we start with 1
and have a button where we can add more
from the remainder of the original 57
*/
var INITIAL_USERS = 1;
/*
If this != null, the datatable has been initialized
*/
var dataTable;
/*
*/
angular
.module("userapp", [])
.controller('TableDemoCtrl', function ($scope, $http) {
/*
GET /ajax/objects.txt and setup the initial 10 $scope.users and put the remainder
in remainingUsers so we have a pool to add new ones from
*/
var remainingUsers = [];
$scope.users = [];
$http({
method: 'GET',
url: '/ajax/objects.txt',
responseType: 'json'
}).then(function (result) {
var allUsers = result.data.data;
allUsers.forEach(function (user) {
// Lets pretend that what in objects.txt is .extn
// is actually a user ID
user.ID = user.extn;
delete user.extn;
});
$scope.users = allUsers.splice(0,INITIAL_USERS);
remainingUsers = allUsers;
});
// We make var users available as a $scope member
$scope.addUserCB = function () {
// Just take one more user from remainingUsers
// Note how this is *all* that is required for the Angular raw table to get updated correctly?
$scope.users.push(remainingUsers.shift());
};
$scope.$watch('users', function () {
setupDataTableUsers($scope.users);
}, true);
// For debugging in the console :-)
// window.s = $scope;
})
// Pure boilerplate that ties the user-link attribute with the #userLinkTemplate
.directive('userLink', function() {
return {
restrict: 'A',
scope: {
user: '=userLink'
},
templateUrl: 'userLinkTemplate'
};
});
/*
Now for the Handlebars / DataTable javascript setup
Notice how most of the view logic is here in javascript.
Here we decide what columns are in the table and what each column contains.
*/
var linkTemplate = Handlebars.compile(
jQuery('#userLinkHandlebarTemplate').html()
);
function setupDataTableUsers(users) {
if (! dataTable)
return;
// Don't want to pollute the pristine users field with a view-specific 'edit'
// field that contains HTML, but we do want HTML in the table
var dataTableUsers = users.map(function (user) {
var userClone = jQuery.extend({}, user);
userClone.edit = linkTemplate({ID: user.ID});
return userClone;
});
/*
How does this perform if there are many users?
Is there a better way than removing everything and adding it all back?
*/
dataTable
.clear()
.rows.add(dataTableUsers)
.draw();
}
jQuery(function () {
dataTable = jQuery('#dataTable').DataTable({
columns: [
{ data: "edit" },
{ data: "name" },
{ data: "position" }
]
});
});
You can jump to the latest bin by adding /latest
to your URL
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + [ | Indents selected lines |
ctrl + ] | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Clone Bin |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |