5. 1. WHAT WE DO: DASHBOARDS AND WIDGETS
Year -- All -- Product -- All -- Country -- All --
13
$1,034
$339
6. 1. WHAT WE DO: DASHBOARDS AND WIDGETS
Initial question:
we use AngularJS with lots of different widgets
how to reuse as much code as possible?
while still being able to tune each widget appearance
Solutions:
Service: not enough (factorize logic but not UI interactions)
Single generic directive: single template problem
Directive composition: a generic base directive plus several
small directives to adapt the template and behavior
TypeScript to the rescue, and much much more!
8. 2. WHY MOVING TO TYPESCRIPT? (1/2)
Potential good solution to factorize our code (more on that
later)
All the goodness of ES6 (classes, fat arrow, template
strings, soon async/await, ...), plus:
statically typed
automatic feedback while developing (think gulp/grunt
watch)
interfaces! description of complex types (e.g. widget
data model) available in a single place and not spread
around the code (Angular is really persmissive for
models)
9. 2. WHY MOVING TO TYPESCRIPT? (2/2)
It's just a Javascript superset, so the migration can be
incremental and smooth, no need to rewrite the app from
scratch
really easy integration with Angular (even if a little scary at
first)
forces to use classes, and then better organize the code
(again Angular is really permissive)
Angular2 is written in TypeScript: Google + Microsoft are
now supporting it
11. 3. ANGULAR + TYPESCRIPT: THE BASICS
Controller
Service
Directive
12. 3. ANGULAR + TYPESCRIPT: THE BASICS - CONTROLLERS
Using ControllerAs syntax, a controller is just a Class
angular
.module('my-lib')
.controller('LoginController', LoginController);
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'mylib/auth/login.template.html',
controller: 'LoginController',
controllerAs: 'vm'
})
13. 3. ANGULAR + TYPESCRIPT: THE BASICS - CONTROLLERS
Example in ES5:
var LoginController = (function () {
function LoginController(loginService, $state) {
this.loginService = loginService;
this.$state = $state;
this.invalidCredentials = false;
if (loginService.isLogged) {
$state.transitionTo('home');
}
}
LoginController.prototype.login = function () {
var _this = this;
this.invalidCredentials = false;
this.loginService.loginWithCrendentials(this.email, this.password)
.catch(function () {
_this.invalidCredentials = true;
});
};
return LoginController;
})();
14. 3. ANGULAR + TYPESCRIPT: THE BASICS - CONTROLLERS
Example in TypeScript: lots of goodness in it
class LoginController {
invalidCredentials = false;
email: string;
password: string;
constructor(private loginService: ILoginService,
private $state: angular.ui.IStateService) {
if (loginMgr2.isLogged) {
$state.transitionTo('home');
}
}
login () {
this.invalidCredentials = false;
this.loginService.loginWithCrendentials(this.email, this.password)
.catch(() => {
this.invalidCredentials = true;
});
}
}
15. 3. ANGULAR + TYPESCRIPT: THE BASICS - SERVICES
Just like Controllers:
class LoginService {
constructor(private Restangular: restangular.IService) {
}
loginWithCrendentials (email: string, password: string) {
return this.Restangular.one('api/token')
.then((apiData) => {
// ... save token
// ... transition to 'home' state
});
}
}
angular
.module('my-lib')
.service(loginService, LoginService);
17. 3. ANGULAR + TYPESCRIPT: EVEN MORE!
ok Angular + TypeScript is cool, but what about code reuse
and our initial question?
Lots of common behavior between
table widget / value widget (= single cell table)
all chart widgets (pie chart, bar chart, curve chart, ...)
18. 3. ANGULAR + TYPESCRIPT: REUSE CODE!
Different ways:
keep the same controller, adapt the template, 2 directives
for the same price!
inherit base controller to inherit basic behavior exposed to
the view (think Mixins when available)
refresh state (reload data from API)
error handling
global data filtering
data export
implement models (e.g. Widgets) as classes completely
outside of Angular's world
19. 3. ANGULAR + TYPESCRIPT: OUR SOLUTION FOR CODE REUSE
keep directives small and simple, and have several if
needed
each customized with its own template
with possibly one base directive to factorize $scope
features and simple properties (replace, ControllerAs, ...)
one base controller and several inherited controllers as
needed
pure TypeScript Widget classes without any Angular
dependency (model/business logic)
21. 4. ANGULAR + TYPESCRIPT: THE GOOD PARTS
easy integration with Angular, especially with ControllerAs
since 1.2
even encourage to use best practises for Angular 2
(ControllerAs => Components)
incremental migration (superset + gradual typing with any)
type infos, type inference and all the good that comes with
it
Interfaces: all the model in one place!
Good debugging experience using source maps with
Chrome
22. 4. ANGULAR + TYPESCRIPT: THE BAD PARTS (1/2)
using 3rd party libraries (missing or outdated typed
definitions): but not such a great problem
dev environment a little more complex (gulp, tsc, tslint,
tsd): actually not so much pain
a little more work sometimes (adding types, directives
more verbose)
23. 4. ANGULAR + TYPESCRIPT: THE BAD PARTS (2/2)
Dealing with class hierarchies: compromise between testability and verbosity
class BaseWidgetController {
private _data: IData;
constructor(private globalFilterService: GlobalFilterService /* other depende
filterData () { return this.globalFilterService.applyFilters(this._data); }
}
class TableWidgetController extends BaseWidgetController {
constructor(private globalFilterService: GlobalFilterService /* other depende
super(globalFilterService, ....);
}
}
/* less verbose alternative - dangerous */
class GlobalFilterService {
/* WARNING: bypass Angular DI and make testing more complex */
static instance() {
angular.element(document.body).injector().get('globalFilterService'
}
applyFilters(...) {...}
}
class BaseWidgetController {
private _data: IData;
25. 4. ANGULAR + TYPESCRIPT: UGLY PARTS?
Not really... or maybe
when coding e2e tests with Protractor + TypeScript:
incompatible Promises types
// selenimum-webdriver type declaration
interface IThenable<T> {
then<R>(opt_callback?: (value: T) => Promise<R>, opt_errback?: (error:
then<R>(opt_callback?: (value: T) => R, opt_errback?: (error: any) => any): P
}
// vs. ES6 type declaration
interface Thenable<R> {
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error:
then<U>(onFulfilled?: (value: R) => U | Thenable<U>, onRejected?: (error:
}
Good luck if you use nodejs with
Q.denodeify or Bluebird.promisify
26. TOWARDS ANGULAR 2.0: ANGULAR IN TYPESCRIPT
If you:
have a growing project in Angular 1.X
want to invest on it for the next couple of years
Do you a favor, go for TypeScript!
Congrats! you'll be half way through the migration to
Angular2!
Angular 2: everything becomes a TypeScript class with
annotations (Component, Directive)
28. QUESTIONS?
Want to work with us at Serenytics?
Interested by Analytics, BI and Startups?
Passionate about Angular and TypeScript? Love Python?
Come and see me, we're looking for an amazing dev /
startuper!
Or contact me at adrien.chauve@serenytics.com