client-side rendering with angularjs
DESCRIPTION
The OpenStack Horizon project provides a web-based User Interface to OpenStack services. It is constructed in two parts: (1) a core set of libraries for implementing a Dashboard; (2) the dashboard implementation that uses the core set of libraries. Horizon uses python django — server side technology Django is a wonderful framework, but a little dated. Pre-dates the rise in client-side and single page applications. Javascript is used for enhancing the user experience In the time since Horizon was first architected, there have been major advances in the design, and best practices for web applications. In particular, the use of more sophisticated and robust client-side javascript frameworks like BackboneJS, AngularJS, MeteorJS, have come to the fore. These applications provide a much more responsive user experience, much cleaner separation between the client and server, enable configuration driven interfaces, and facilitate more modular testing. This in turn, results in shorter development cycles, more testable software, and above all, a better user experience. In this presentation, we share some of our recent work in re-architecting parts of Horizon to take advantage of these new technologies. We discuss some of the technologies we use, our application architecture, and some of the pitfalls to avoid.TRANSCRIPT
![Page 1: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/1.jpg)
Client-side Rendering with AngularJS
OpenStack Summit, Paris
David Lapsley
@devlaps, [email protected]
November 3, 2014
![Page 2: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/2.jpg)
Client-side rendering in production
![Page 3: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/3.jpg)
Client-side Rendering
“Full” dataset search
Cache up to 1K records client-side“Full” pagination
![Page 4: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/4.jpg)
Real-time DataUpdates every 5s
Increased platform visibility
Every node instrumented
![Page 5: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/5.jpg)
Historical Metrics
Up to 1 year of data
Increased platform visibility Every node instrumented
Convenient access
![Page 6: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/6.jpg)
OpenStack Horizon
Architecture
![Page 7: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/7.jpg)
Django Stack
![Page 8: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/8.jpg)
Horizon Stack
![Page 9: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/9.jpg)
Horizon Stack Extended
![Page 10: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/10.jpg)
AngularJS
![Page 11: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/11.jpg)
Core concepts
● Model View Controller framework
● Client-side templates
● Data binding
● Dependency injection
![Page 12: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/12.jpg)
Hello Worldindex.html
<html ng-app>
<head>
<script src="angular.js"></script>
<script src="controllers.js"></script>
</head>
<body>
<div ng-controller='HelloController'>
<p>{{greeting.text}}, World</p>
<button ng-click="action()">Alert</button>
</div>
</body>
</html>
controllers.js
function HelloController($scope) {
$scope.greeting = { text: 'Hello' };
$scope.action = function() {
alert('Action!');
};
}
AngularJS
By: Brad Green; Shyam Seshadri
Publisher: O'Reilly Media, Inc.
Pub. Date: April 23, 2013
![Page 13: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/13.jpg)
Hello World
![Page 14: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/14.jpg)
Hello World
![Page 15: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/15.jpg)
Adding a new Horizon feature
with AngularJS
![Page 16: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/16.jpg)
Directory Structureopenstacksummit/
hypervisors/
__init__.py
panel.py
urls.py
views.py
tables.py
tests.py
templates/openstacksummit/hypervisors/
index.html
static/openstacksummit/hypervisors/js/
hypervisors-controller.js
rest/nova/
__init__.py
hypervisor.py
instance.py
![Page 17: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/17.jpg)
REST Resource: hypervisors.pyclass HypervisorResource(resource.BaseNovaResource):
pk = fields.CharField(attribute="pk", _("Primary Key"), hidden=True)
hypervisor_hostname = fields.CharField(attribute='hypervisor_hostname',
sortable=True,
searchable=True)
…
actions = fields.ActionsField(attribute='actions',
actions=[HypervisorViewLiveStats,
HypervisorEnableAction,
HypervisorDisableAction],
title=_("Actions"),
sortable=True)
class Meta:
authorization = auth.RestAuthorization()
list_allowed_methods = ['get']
resource_name = '^hypervisor'
field_order = ['pk', 'hypervisor_hostname', 'hypervisor_type', 'vcpus',
'vcpus_used', 'memory_mb', 'memory_mb_used',
'running_vms', 'state', 'status', 'actions']
![Page 18: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/18.jpg)
Controller: hypervisor-controller.js
horizonApp.controller('TableController',
function($scope, $http) {
$scope.headers = headers;
$scope.title = title;
$http.get('/rest/api/v1/nova/instance/').success(
function(data, status, headers, config) {
$scope.instances = transform(data.objects);
});
});
horizonApp.controller('ActionDropdownController',
function($scope) {
$scope.status = {
isopen: false
};
$scope.toggleDropdown = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.status.isopen = !$scope.status.isopen;
};
$scope.action = function(action, id) {
// Perform action.
};
…
});
![Page 19: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/19.jpg)
View: index.html
{% extends 'base.html' %}
{% load i18n horizon humanize sizeformat %}
{% block title %}{% trans 'Hypervisors' %}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('All
Hypervisors') %}
{% endblock page_header %}
{% block main %}
![Page 20: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/20.jpg)
View: index.html
<div ng-controller="TableController">
<table class="...">
<thead>
<tr class="...">
<th class="...">
<h3 class="...">{$ title $}</h3>
</th>
</tr>
<tr class="...">
<th class="..." ng-repeat='header in headers'>
<div class="...">{$ header.name $}</div>
</th>
</tr>
</thead>
![Page 21: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/21.jpg)
View: index.html<tr ng-repeat="instance in instances">
<td ng-repeat="datum in instance.data">{$ datum $}</td>
<td class="...">
<div ng-controller="ActionDropdownController">
<div class="..." dropdown>
<button class="..."
ng-click="action(instance.actions[0], instance.name)">
{$ instance.actions[0].verbose_name $}
</button>
...
<div class="...">
<li class="..." ng-repeat="action in instance.actions">
<a href="#" class="..."
ng-click="$parent.action(action,parent.instance.name)">
{$ action.verbose_name $}
</a>
</li>
</ul>
</div>
</td>
</tr>
</table>
![Page 22: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/22.jpg)
Client-side Rendering
“Full” dataset search
Cache up to 1K records client-side“Full” pagination
![Page 23: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/23.jpg)
Why?
![Page 24: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/24.jpg)
Advantages
● Clean split between server and client side
● Significantly cleaner, terser, easier to
understand client-side code
● Significant easier to improve UX
● Client- and server-side code can be
developed and tested independently
● Faster feature velocity
![Page 25: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/25.jpg)
Better UX
Faster!
![Page 27: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/27.jpg)
If this sounds interesting…
http://jobs.metacloud.com
We are hiring!
![Page 28: Client-side Rendering with AngularJS](https://reader034.vdocument.in/reader034/viewer/2022052508/559441eb1a28ab01308b4586/html5/thumbnails/28.jpg)