Skip to content

Instantly share code, notes, and snippets.

@x1ddos
Last active December 18, 2015 17:59
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save x1ddos/5822385 to your computer and use it in GitHub Desktop.
Save x1ddos/5822385 to your computer and use it in GitHub Desktop.
AngularJS 1.1.5 + Google Closure Library (just a little) + Closure Compiler (obviously) experiment
<html ng-app="ng-demo-app">
<head>
<title>AngularJS simple app demo</title>
</head>
<body ng-controller="MainCtrl">
<input type="text" ng-model="name" ng-required>
<div>{{name}}</div>
<div ng-controller="ChildCtrl">
<input type="text" ng-model="salut">
<div>{{salutation}}</div>
</div>
<p current-time="{{timeFormat}}"></p>
<p>format:
<select ng-model="timeFormat" ng-options="o for o in timeOpts"></select>
</p>
<script src="/angular.min.js"></script>
<script src="ng-demo-app.min.js"></script>
</body>
</html>
(function(){ 'use strict';function b(a) {
a && (this.a = a, this.a.name = "alex")
}
b.$inject = ["$scope"];
b.prototype.getName = function() {
return(this.a.name || "anonymous")[0].toUpperCase() + (this.a.name || "anonymous").slice(1)
};
function c(a) {
b.call(this);
this.d = this.d.bind(this);
a && (this.a = a, a = function() {
return[this.a.name, this.a.salut]
}.bind(this), this.a.$watch(a, this.d, !0))
}
(function() {
function a() {
}
a.prototype = b.prototype;
c.l = b.prototype;
c.prototype = new a
})();
c.$inject = ["$scope"];
c.prototype.d = function() {
this.a.salutation = (this.a.salut || "hello")[0].toUpperCase() + (this.a.salut || "hello").slice(1) + ", " + this.getName() + "!"
};
function d(a, e) {
this.$timeout = a;
this.i = e;
this.timeFormat = "medium";
this.link = this.link.bind(this);
this.b = this.b.bind(this);
this.e = this.e.bind(this)
}
d.prototype.c = "currentTime";
d.prototype.h = "medium short fullDate longDate mediumDate shortDate mediumTime shortTime".split(" ");
d.prototype.f = "medium";
function f(a, e) {
return{link:(new d(a, e)).link}
}
f.$inject = ["$timeout", "dateFilter"];
d.prototype.link = function(a, e, h) {
this.scope = a;
this.j = e;
this.g = h;
this.g.$observe(this.c, this.e);
this.b()
};
d.prototype.e = function() {
this.timeFormat = this.g[this.c] || this.f;
this.b()
};
d.prototype.b = function() {
this.$timeout.cancel(this.k);
var a = this.i(new Date, this.timeFormat);
this.j.html("Local time: " + a);
this.k = this.$timeout(this.b, 1E3)
};
function g(a) {
a.timeOpts = d.prototype.h;
a.timeFormat = d.prototype.f
}
g.$inject = ["$rootScope"];
angular.module("ng-demo-app", []).controller("MainCtrl", b).controller("ChildCtrl", c).directive(d.prototype.c, f).run(g);
}).call(window)
// Compile with:
//
// java -jar $COMPILER_JAR \
// --define=goog.DEBUG=false \
// --warning_level=VERBOSE \
// --summary_detail_level=3 \
// --compilation_level=ADVANCED_OPTIMIZATIONS \
// --language_in ECMASCRIPT5_STRICT --angular_pass --formatting PRETTY_PRINT \
// --externs ~/src/closure/compiler/contrib/externs/angular.js \
// --js $CLOSURE_LIB/closure/goog/base.js \
// --js ng-demo-app.src.js --output_wrapper '(function(){ %output% }).call(window)' \
// > ng-demo-app.min.js
/**
* @fileoverview AngularJS simple app demo
*/
goog.provide('demos.ng.simple.MainCtrl');
goog.provide('demos.ng.simple.ChildCtrl');
/**
* Main controller
* @param {angular.Scope=} $scope
* @constructor
* @ngInject
*/
demos.ng.simple.MainCtrl = function($scope) {
if ($scope) {
this.$scope = $scope;
/**
* @type {string}
* @expose
*/
this.$scope.name = 'alex';
}
}
demos.ng.simple.MainCtrl.prototype.getName = function() {
return titleize(this.$scope.name || 'anonymous');
}
/**
* Child controller
* @param {angular.Scope=} $scope
* @constructor
* @extends {demos.ng.simple.MainCtrl}
* @ngInject
*/
demos.ng.simple.ChildCtrl = function($scope) {
goog.base(this);
this.onScopeChange = this.onScopeChange.bind(this);
/**
* @type {string}
* @expose
*/
this.$scope.salut;
/**
* @type {string}
* @expose
*/
this.$scope.salutation;
if ($scope) {
this.$scope = $scope;
var watcher = (function(){
return [this.$scope.name, this.$scope.salut]
}).bind(this);
this.$scope.$watch(watcher, this.onScopeChange, true);
}
}
goog.inherits(demos.ng.simple.ChildCtrl, demos.ng.simple.MainCtrl);
/**
* Callback for when name or salut scope values change.
* Updates salutation scope value.
*/
demos.ng.simple.ChildCtrl.prototype.onScopeChange = function() {
this.$scope.salutation = this.getSalutation();
}
/**
* Returns a "hello, name" salutation using name and salut from the scope.
*/
demos.ng.simple.ChildCtrl.prototype.getSalutation = function() {
var salut = this.$scope.salut || 'hello';
return titleize(salut) + ', ' + this.getName() + '!';
}
/**
* A directive that displays current local time.
* @constructor
*/
demos.ng.simple.TimeDirective = function($timeout, dateFilter) {
this.$timeout = $timeout;
this.dateFilter = dateFilter;
/** @type {string} */
this.timeFormat = 'medium';
/** @type {angular.$q.Promise} */
this.timerPromise;
this.link = this.link.bind(this);
this.updateTime = this.updateTime.bind(this);
this.onTimeFormatChange = this.onTimeFormatChange.bind(this);
/** @type {angular.Scope} */
this.scope;
/** @type {angular.JQLite} */
this.elem;
/** @type {angular.Attributes} */
this.attrs;
}
/** @const */
demos.ng.simple.TimeDirective.prototype.DIR_NAME = 'currentTime';
/** @const */
demos.ng.simple.TimeDirective.prototype.TIME_OPTS = [
'medium', 'short', 'fullDate', 'longDate', 'mediumDate', 'shortDate',
'mediumTime', 'shortTime'
]
/** @const */
demos.ng.simple.TimeDirective.prototype.DEFAULT_TIME_FORMAT = 'medium';
/**
* TimeDirective factory.
* @return {Object}
* @ngInject
*/
demos.ng.simple.TimeDirective.factory = function($timeout, dateFilter) {
var dir = new demos.ng.simple.TimeDirective($timeout, dateFilter);
return {
link: dir.link
}
}
/**
* Linking function.
* @param {angular.Scope} scope
* @param {angular.JQLite} elem
* @param {angular.Attributes} attrs
*/
demos.ng.simple.TimeDirective.prototype.link = function(scope, elem, attrs) {
this.scope = scope;
this.elem = elem;
this.attrs = attrs;
this.attrs.$observe(this.DIR_NAME, this.onTimeFormatChange);
this.updateTime();
}
/**
* Watcher callback for when a user selects a new time format.
* @param {*} val
*/
demos.ng.simple.TimeDirective.prototype.onTimeFormatChange = function(val) {
this.timeFormat = this.attrs[this.DIR_NAME] || this.DEFAULT_TIME_FORMAT;
this.updateTime();
}
/**
* Updates element with the current time each second.
*/
demos.ng.simple.TimeDirective.prototype.updateTime = function() {
this.$timeout.cancel(this.timerPromise);
var now = new Date();
var formatted = this.dateFilter(now, this.timeFormat);
this.elem.html('Local time: ' + formatted);
this.timerPromise = this.$timeout(this.updateTime, 1000);
}
// ----------------------------------------------------------------------------
// the app
/**
* Runs only once at startup time
* @param {angular.Scope} $rootScope
* @ngInject
*/
function onAppStartup($rootScope) {
/**
* Time format options for select box
* @type {Array.<string>}
* @expose
*/
$rootScope.timeOpts =
demos.ng.simple.TimeDirective.prototype.TIME_OPTS;
/**
* @type {string}
* @expose
*/
$rootScope.timeFormat =
demos.ng.simple.TimeDirective.prototype.DEFAULT_TIME_FORMAT;
}
/** @type {angular.Module} */
var app = angular.module('ng-demo-app', []).
controller('MainCtrl', demos.ng.simple.MainCtrl).
controller('ChildCtrl', demos.ng.simple.ChildCtrl).
directive(demos.ng.simple.TimeDirective.prototype.DIR_NAME,
demos.ng.simple.TimeDirective.factory).
run(onAppStartup);
// ----------------------------------------------------------------------------
// utils
/**
* Changes first letter to the upper case
* @param {string} str
* @return {string}
*/
function titleize(str) {
if (!str) return str;
return str[0].toUpperCase() + str.slice(1);
}
@x1ddos
Copy link
Author

x1ddos commented Jun 20, 2013

Might look like an overkill but on a huge codebase could be useful.

@tschiela
Copy link

Thanks for the code snippet. I think this approach increase the maintainability and testability. We only have one problem: If we use a directive multiple times on a site. Directive.factory will only be called once. So all directives on sites share the same Directive object. Do you have an idea whats going wrong here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment