Transcript
Page 1: Client-side Rendering with AngularJS

Client-side Rendering with AngularJS

OpenStack Summit, Paris

David Lapsley

@devlaps, [email protected]

November 3, 2014

Page 2: Client-side Rendering with AngularJS

Client-side rendering in production

Page 3: Client-side Rendering with AngularJS

Client-side Rendering

“Full” dataset search

Cache up to 1K records client-side“Full” pagination

Page 4: Client-side Rendering with AngularJS

Real-time DataUpdates every 5s

Increased platform visibility

Every node instrumented

Page 5: Client-side Rendering with AngularJS

Historical Metrics

Up to 1 year of data

Increased platform visibility Every node instrumented

Convenient access

Page 6: Client-side Rendering with AngularJS

OpenStack Horizon

Architecture

Page 7: Client-side Rendering with AngularJS

Django Stack

Page 8: Client-side Rendering with AngularJS

Horizon Stack

Page 9: Client-side Rendering with AngularJS

Horizon Stack Extended

Page 10: Client-side Rendering with AngularJS

AngularJS

Page 11: Client-side Rendering with AngularJS

Core concepts

● Model View Controller framework

● Client-side templates

● Data binding

● Dependency injection

Page 12: Client-side Rendering with AngularJS

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

Hello World

Page 14: Client-side Rendering with AngularJS

Hello World

Page 15: Client-side Rendering with AngularJS

Adding a new Horizon feature

with AngularJS

Page 16: Client-side Rendering with AngularJS

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

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

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

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

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

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

Client-side Rendering

“Full” dataset search

Cache up to 1K records client-side“Full” pagination

Page 23: Client-side Rendering with AngularJS

Why?

Page 24: Client-side Rendering with AngularJS

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

Better UX

Faster!

Page 26: Client-side Rendering with AngularJS

Thank You

David Lapsley

@devlaps, [email protected]

Page 27: Client-side Rendering with AngularJS

If this sounds interesting…

http://jobs.metacloud.com

We are hiring!

Page 28: Client-side Rendering with AngularJS

Recommended