27
Admin UI Introduction to developing using AngularJS Xavier Butty Software Engineer for the open minded

Opencast Admin UI - Introduction to developing using AngularJS

  • Upload
    buttyx

  • View
    110

  • Download
    2

Embed Size (px)

Citation preview

Admin UIIntroduction to developing using AngularJS

Xavier Butty Software Engineer

for the open minded

– for the open minded

This is not an extensive AngularJS course…

.. but a short introduction to this framework using portions of the new Admin UI

Aimed to help developer to start extending the Admin UI

First name, Last name Position

for the open mindedfor the open minded

01

Base conceptsbehind AngularJS

– for the open minded

Model-View-Whatever works for youTemplate

<!doctype html> <html ng-app="myApp"> <head> <title>My little AngularJS app</title> </head> <body> Hello {{ user }}! <script src="angular.js"></script> </body> </html>

Model (Scope)

{ 'user': 'Georges Bregy' }

Controller

Directive

View (DOM)

Resource

Compilation

Service

– for the open minded

Data binding

Two-way binding

Use Markup {{ myVar }} to represent data in the template

Rendered into a live view

Updating the view update the model…

…and vice-versa

– for the open minded

Data binding<!doctype html><html ng-app="myApp"> <head> <title>My little AngularJS app</title> </head> <body> <h1>Welcome {{ user }}!</h1>

<ul> <li ng-repeat="link in links"> <a ng-href="{{link.href}}">{{link.name}}</a> </li> <ul> <select ng-model="currentLang" name="language" ng-options="l.name for l in languages"> <option value="">-- choose language --</option> </select>

</span> <script src="angular.js"></script> </body></html>

{ 'user': 'Georges Bregy' 'links': [ { 'href': 'http://www.google.ch', 'name': 'Search' }, { 'href': 'http://www.opencastcommunity.com', 'name': 'Opencast community' } ], 'languages': [ { 'name': 'English' }, { 'name': 'German' } ],

'currentLang': { 'name': 'English' };}

– for the open minded

Scope

Model attached to a portion of a view

One root scope…

…with unlimited child scopes that inherit from the parent scope

– for the open minded

<!doctype html> <html lang="en" ng-app="adminNg"> <head>…</head> <body ng-cloak ng-controller="ApplicationCtrl" ng-click="bodyClicked()">

<header ng-controller="NavCtrl" class="primary-header"> <div class=“header-branding”>…</div> <nav id="nav-dd-container" class="nav-dd-container">

<div class="nav-dd" id="lang-dd" old-admin-ng-dropdown=""> <div class="lang" ng-class="currentLanguageCode"></div> <ul class="dropdown-ul"> <li> <a href="#" ng-repeat="language in availableLanguages | orderBy:'displayLanguage'" ng-click="changeLanguage(language.code)"> <i class="lang {{ toLanguageClass(language) }}"></i>{{ language.displayLanguage }} </a> </li> </ul> </div>

<div ng-if="documentationUrl" class="nav-dd help" id="help-dd" ng-click="toDoc()"></div>

<div class="nav-dd" id="user-dd" old-admin-ng-dropdown=“”>…</div> </nav> </header>

<footer id="main-footer" ng-controller="NavCtrl"> <div class="default-footer"> <div ng-if="version.version" class="meta"> Opencast Video Capture Software (v.{{ version.version }} - build: {{ version.buildNumber }}) </div> <div ng-if="feedbackUrl" class="feedback-btn" id=“feedback-btn”>…</div> </div> </footer> </body> </html>

Root scopescope ApplicationCtrl

scope NavCtrl

x child scopes (ng-repeat)

scope NavCtrl

– for the open minded

Dependancy injection

Injection of defined component

Most common way: Inline Array Annotation

Alternative: Manual injection with $inject

// A controller for global page navigationangular.module('adminNg.controllers').controller('NavCtrl', ['$scope', '$rootScope', '$location', '$window', '$resource', '$routeParams', 'Language', function ($scope, $rootScope, $location, $window, $resource, $routeParams, Language) {

$scope.category = $routeParams.category || $rootScope.category;

$scope.availableLanguages = [];

First name, Last name Position

for the open mindedfor the open minded

02

Main components

– for the open minded

Modules

Use to organise the components of an app in package

Simplify unit tests and make them faster. Only the required modules can be loaded.

For the admin UI, we have modules for:

Main app (adminNG), Controllers, Services, Filters, Directives

Other module are external components

// A controller for global page navigationangular.module('adminNg.controllers').controller('NavCtrl', ['$scope', '$rootScope', '$location', '$window', '$resource', '$routeParams', 'Language', function ($scope, $rootScope, $location, $window, $resource, $routeParams, Language) {

$scope.category = $routeParams.category || $rootScope.category;…sh

ared

/con

trol

lers

/na

viga

tionC

ontr

olle

r.js

– for the open minded

Controllers

Set the initial state of a scope

Linked to a defined portion of a view

Allow to augment the scope

Override properties/methods inherit defined in parent controllers

In the new Admin UI:

/shared/controllers/**/*

/modules/*/controllers

– for the open minded

<header ng-controller="NavCtrl" class="primary-header"> <div class="header-branding"> <div class="text-logo">Opencast</div> <div class="logo-tag">Beta</div> </div> <nav id="nav-dd-container" class="nav-dd-container"> <div class="nav-dd" id="lang-dd" old-admin-ng-dropdown=""> <div class="lang" ng-class="currentLanguageCode"></div> <ul class="dropdown-ul"> <li><a href="#" ng-repeat="language in availableLanguages | orderBy:'displayLanguage'" ng-click="changeLanguage(language.code)"> <i class="lang {{ toLanguageClass(language) }}"></i>

// A controller for global page navigationangular.module('adminNg.controllers').controller('NavCtrl', ['$scope', '$rootScope', '$location', '$window', '$resource', '$routeParams', 'Language', function ($scope, $rootScope, $location, $window, $resource, $routeParams, Language) {

$scope.category = $routeParams.category || $rootScope.category;

$scope.availableLanguages = [];

$scope.changeLanguage = function (key) { Language.changeLanguage(key); };

$scope.toLanguageClass = function (language) { return Language.$convertLanguageToCode(language.code); };

/sha

red/

cont

rolle

rs/

navi

gatio

nCon

trol

ler.j

sin

dex.

htm

lDefinition

Usage

– for the open minded

Services

Create custom object shareable through the App

Lazily instantiated Only instantiated when a component requires it

SingletonEach component requiring a service get a reference to the

same instance instantiated by the service factory.

In the new Admin UI : /shared/services/**/*

– for the open minded

angular.module('adminNg.services') .factory('AuthService', ['IdentityResource', function (IdentityResource) { var AuthService = function () { var me = this, isAdmin = false, isUserLoaded = false, callbacks = [], identity, isAuthorizedAs = function (role) { if (angular.isUndefined(me.user.roles)) { return false; } return isAdmin || (angular.isArray(me.user.roles) && me.user.roles.indexOf(role) > -1) || me.user.roles === role; };

this.user = {};

this.loadUser = function () { identity = IdentityResource.get(); identity.$promise.then(function (user) { var adminRole = user.org.adminRole; me.user = user; isAdmin = angular.isDefined(adminRole) && user.roles.indexOf(adminRole) > -1; isUserLoaded = true; angular.forEach(callbacks, function (item) { isAuthorizedAs(item.role) ? item.success() : item.error(); }); }); };

this.getUser = function () { return identity; };

this.loadUser(); };

return new AuthService(); }]);

/sha

red/

serv

ices

/aut

hSer

vice

.js

– for the open minded

Resources

Synchronisation with the RESTfull data source

Natively use JSON for the data transfer

Using the $http service

In the new Admin UI : /shared/resources/**/*

– for the open minded

angular.module('adminNg.resources') .factory('AclResource', ['$resource', function ($resource) { return $resource('/admin-ng/acl/:id', { id: '@id' }, { get: { method: 'GET', transformResponse: function (data) { return JSON.parse(data); } }, save: { method: 'PUT', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, transformRequest: function (data) { if (angular.isUndefined(data)) { return data; }

return $.param({ name : data.name, acl : JSON.stringify({acl: data.acl}) }); } } }); }]);

/sha

red/

reso

urce

s/ac

lRes

ourc

e.js

AclResource.save({id: $scope.resourceId}, { acl: { ace: ace }, name: $scope.metadata.name}, function () { Notifications.add('success', 'ACL_UPDATED', 'acl-form');}, function () { Notifications.add('error', 'ACL_NOT_SAVED', 'acl-form');});

Resource definition

Usage

– for the open minded

Directives

Allow to create custom view component

Can be cascaded

Each directive instance has its own scope

Take care to not overload the stack!

Non-native element wrapped in directive have to be managed carefully!

– for the open minded

angular.module('adminNg.directives').directive('withRole', ['AuthService', function (AuthService) { return { priority: 1000, link: function ($scope, element, attr) { element.addClass('hide');

AuthService.userIsAuthorizedAs(attr.withRole, function () { element.removeClass('hide'); }, function () { element.remove(); }); } };}]);

<div class="btn-group">

<button data-open-modal="user-modal" data-action="add" class="add" with-role="ROLE_UI_USERS_CREATE"> <i class="fa fa-plus"></i> <span translate="USERS.ACTIONS.ADD_USER"><!--Add User--></span> </button>

</div>

/sha

red/

dire

ctiv

es/w

ithR

oleD

irec

tive.

js

Usage

Directive definition

– for the open minded

Filters

Function to be used within the expression {{ value | filter:argument1 }}

Use it for input formatting - Date presentation - Text translation - Array presentation

Can also be used within the controller

– for the open minded

angular.module('adminNg.filters') .filter('trusted', ['$sce', function ($sce) { return function(url) { return $sce.trustAsResourceUrl(url); }; }]);

<video id="player" ng-if="controls === 'false'"> <source ng-repeat="preview in video.previews" ng-src="{{ preview.uri | trusted }}" type="video/mp4" /> Your browser does not support HTML5 video.</video>

/sha

red/

filte

rs/t

rust

edR

esou

rceU

rlFi

lter

Filter definition

Usage

First name, Last name Position

for the open mindedfor the open minded

Jasminefor unit testing

03

– for the open minded

How does a Jasmine specs look like?describe('Navigation controller', function () {

var $scope, $httpBackend, Language;

beforeEach(module('adminNg'));

beforeEach(module(function ($provide) {

var service = {

configureFromServer: function () {},

formatDate: function (val, date) { return date; },

formatTime: function (val, date) { return date; },

changeLanguage: function () {},

getLanguageCode: function () { return 'ja_JP'; },

getLanguage: function () { return {}; },

First name, Last name Position

for the open mindedfor the open minded

04

Let’s work on it!

– for the open minded

The summary of "create event" show empty element

Some items show in the summary of the new event wizard are empty, and should therefore not be displayed.

– for the open minded

Delete series and events

Add (x) icon in the events and series tableview to allow deletion of single Events/Series

Questions?

thanks for your attentionXavier Butty Software Engineer

for the open minded