Application widgets with angular.js
Behind the scenes with angular.injector and angular.element
Single page app?
Content driven
A lot of content, tons of pages, very SEO relevant...
web application
Less content, tons of interactions, less SEO relevant...
Let's mix it Up!
Content driven website
with application widgets
angular
bootstrap
no... not the twitter thingy!
Auto-bootstrap
<html> <body ng-app="myApp"> <p>Hello {{name}}!</p> </body> </html>
do-it-yourself
<html> <body data-ng-boot="myApp"> <p>Hello {{name}}!</p> </body> </html>
$(function() { $('[data-ng-boot]').each(function() { angular.bootstrap(this, [ $(this).data('ngBoot') ]); }); });
Multiple Apps on one page
Why one if we can have many???
<html> <body> <section data-ng-boot="widgetOne"> <p>Hello {{name}}!</p> </section> <section data-ng-boot="widgetTwo"> <p>Hello {{name}}!</p> </section> </body> </html>
angular.module('widgetOne', []) .run(function($rootScope) { $rootScope.name = 'Angular'; }); angular.module('widgetTwo', []) .run(function($rootScope) { $rootScope.name = 'Multi-boot'; }); $(function() { $('[data-ng-boot]').each(function() { angular.bootstrap(this, [ $(this).data('ngBoot') ]); }); });
150 KB JavascRipt
for A widget that might not Even exists on the Page?!
Lazy loading of Angular.Js and widgets
<html> <body> <section data-ng-boot="widgetOne:widget-one.js"> <p>Hello {{name}}!</p> </section> <section data-ng-boot="widgetTwo:widget-two.js"> <p>Hello {{name}}!</p> </section> </body> </html>
$(function() { $('[data-ng-boot]').each(function() { var $element = $(this); var split = $element.data('ngBoot').split(':'); $LAB.script(function loadAngular() { if(!window.angular) { return '//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js'; } }).wait(function() { $LAB.script(function loadModules() { if(split.length > 1) { return split.splice(1); } }).wait(function() { angular.bootstrap($element, [ split[0] ]); }); }); }); });
Access
Angular
from
the outside
element & injector
<html> <body ng-app="myApp"> Message: {{message}} </body> </html>
angular.module('myApp', []) .value('name', 'World'); var element = angular.element($('[ng-app="myApp"]')); setTimeout(function() { element.scope().message = 'Test'; element.scope().$digest(); }, 2000); setTimeout(function() { var name = element.injector().get('name'); var reversed = name.split('').reverse().join(''); element.scope().message = 'Welcome ' + reversed + '!'; element.scope().$digest(); }, 4000);
LET THEM
COMMUNICATE!
Runtime Architecture
with multiple apps
Direct communication
by addressing elements
function AlienMessageController($scope) { $scope.sendMessage = function(alienRootElementId) { var alienRootScope = angular.element('#' + alienRootElementId).scope(); alienRootScope.remoteMessages = alienRootScope.remoteMessages || []; alienRootScope.remoteMessages.push($scope.message); alienRootScope.$evalAsync(); }; } angular.module('widgetOne', []) .controller('AlienMessageController', AlienMessageController); angular.module('widgetTwo', []) .controller('AlienMessageController', AlienMessageController); $(function() { $('[data-ng-boot]').each(function() { angular.bootstrap(this, [ $(this).data('ngBoot') ]); }); });
PUB / SUB with message hub
function MessageHub() { this.subscriptions = {}; this.subscribe = function(type, scope) { if(type instanceof Array) { type.forEach(function(typeElement){ this.subscribe.call(this, typeElement, scope); }.bind(this)); } this.subscriptions[type] = this.subscriptions[type] || []; if(this.subscriptions[type].indexOf(scope) === -1) { this.subscriptions[type].push(scope); } }; this.publish = function(senderScope, type, message) { if(this.subscriptions[type]) { this.subscriptions[type].forEach(function(scope) { scope.messages = scope.messages || []; scope.messages.push({ sender: senderScope, type: type, message: message }); scope.$evalAsync(); }); } }; }
function MessageHub() { this.subscriptions = {}; this.subscribe = function(type, scope) { if(type instanceof Array) { type.forEach(function(typeElement){ this.subscribe.call(this, typeElement, scope); }.bind(this)); } this.subscriptions[type] = this.subscriptions[type] || []; if(this.subscriptions[type].indexOf(scope) === -1) { this.subscriptions[type].push(scope); } }; this.publish = function(senderScope, type, message) { if(this.subscriptions[type]) { this.subscriptions[type].forEach(function(scope) { scope.messages = scope.messages || []; scope.messages.push({ sender: senderScope, type: type, message: message }); scope.$evalAsync(); }); } }; }
Thanks!
@GionKunz
Frontend Developer & Consultant
Application Widgets with Angular.js - Behind the scenes with angular.injector and angular.element
By Gion Kunz
Application Widgets with Angular.js - Behind the scenes with angular.injector and angular.element
This presentation will give you an insight into some options how to handle application widgets on a content driven website with Angular.js and shows you some basic internal concepts of Angular.js.
- 2,927