- Decorador:
@Application
- É um
Module
, mas com uma notação de seletor que indica o elemento base da aplicação
Exemplo:
app/app.ts
import {Application, Inject, Constant, bootstrap} from 'tng'
import {Components} from './components'
import {Services} from './services/concrete/services'
import {Storage} from './services/abstract/storage'
var version = Constant('version', '1.3.2');
@Application({
element: document,
dependencies: ['ngRoute', Components, Services, version]
})
class TodoApp {
onRun(@Inject('storage') storage: Storage): void {
storage.clean();
}
}
bootstrap(TodoApp);
- Dacorador:
@Module
- Equivalente a um módulo do Angular, agregando submódulos, serviços e componentes
- Permite fornecer funções de configuração:
- através da anotação
config
- através de método
onConfig()
implementado na classe do módulo
- através da anotação
- Permite fornecer funções de inicialização:
- através da anotação
run
- através de método
onRun()
implementado na classe do módulo
- através da anotação
- Informa-se outros módulos, serviços, componentes, decoradores, filtros, animacoes,
valores e constantes através da anotação
dependencies
- Pode-se depender de outros módulos regulares, não implementados usando TNG, bastando apenas
informar seus nomes em
dependencies
Exemplos:
Arquivo: app/components.ts
import {Module} from 'tng'
import {Todo} from './components/todo/todo'
import {TodoItem} from './components/todo/todo-item'
@Module({
dependencies: ['ui.bootstrap', Todo, TodoItem]
})
export class Components {
}
Arquivo: app/services/services.ts
import {Module, Inject} from 'tng'
import {Storage} from './concrete/storage/storage'
import ICookiesServiceProvider = ng.cookies.ICookiesServiceProvider
@Module({
dependencies: ['ngCookies', Storage]
})
export class Services implements Module {
onConfig(@Inject('$cookiesProvider') $cookiesProvider: ICookiesServiceProvider): void {
// STUB
}
}
- Decorador:
@Constant
import {Constant, Module} from 'tng'
var version = Constant('version', '1.2.3');
@Module({
dependencies: [version]
})
export class MyModule {
}
- Decorador:
@Value
import {Value, Module} from 'tng';
var state = Value('state', {current: 'stoped', next: 'moving'});
@Module({
dependencies: [state]
})
...
- Decorator:
@Service
- Diferentemente de
angular.Module.service()
, que constrói o serviço comnew
, são construídos com$injector.instantiate()
, e portanto seus construtores podem receber injeções - Podem também ser construídos por uma fábrica, referenciada pela anotação
factory
em@Service
e invocada por$injector.invoke()
(vide https://docs.angularjs.org/api/auto/service/$provide#factory) - Podem ainda ser fornecidos por um provedor, referenciado pela anotação
provider
em@Service
e invocada por$injector.invoke()
(vide https://docs.angularjs.org/api/auto/service/$provide#provider)
Exemplos:
Arquivo: app/concrete/services/storage.ts
import {Module, Inject} from 'tng';
@Service({
name: 'storage'
})
export class Storage {
private $cookies: ng.cookies.ICookiesService;
// Dependências são injetáveis no construtor
constructor(@Inject('$cookies') $cookies:ng.cookies.ICookiesService) {
this.$cookies = $cookies;
}
read(key: string):any {
...
}
write(key: string, value:any) {
...
}
clean() {
...
}
}
- Decorador:
@Directive
- Não possui
@View
(use@Component
) - Não podem ser roteadas (
@Route
)
- Decorator:
@Component
- São diretivas que possuem templates, e têm algumas opções forçadas:
- Para
@Component
:- scope é orbigatório, ou
true
ou{}
, sendotrue
o padrão - ??? bindToController
- scope é orbigatório, ou
- Exige
@View
e algum template informado
- Para
- Podem ser roteadas (
@Route
) - A classe do component é o ViewModel (controller) do component
- Templates, se necessários, podem ser fornecidos pelo decorador
@View
:- através da anotação
template
, podendo ser:- uma string representando o template
- uma função a ser invocada com
$injector.invoke()
e que retorna uma string representando o template
- através da anotação
templateUrl
, podendo ser:- uma string contendo URL para o arquivo do template
- uma função a ser invocada com
$injector.invoke()
e que retorna uma string contendo a URL
- através da anotação
- Uma função de compilação, invocada com
$inject.invoke()
, pode ser referenciada na anotaçãocompile
em@Component
- Para a função as funções referenciadas em
compile
,template
etemplateUrl
, há injeções locais disponíveis:element
: elemento template onde a diretiva foi declaradaattributes
: lista normalizada de atributos nesse elemento template, compartilhada com as demais diretivas do elemento
- Uma função de ligação, invocada com
$inject.invoke()
, pode ser referenciada na anotaçãolink
em@Component
. Para esta função, estão disponíveis as seguintes injeções locais:element
: instancia do elemento, onde a diretiva será usadaattributes
: lista normalizada de atributos nesse elemento, compartilhada com as demais diretivas do elementoscope
: escopo a ser usado pela diretivacontroller
: TODOtransclude
: TODO
- Com exceção de
controller
, as injeções locais disponíveis alink
também estão disponíveis ao construtor do componente (ViewModel) - ??? Tornar PrePost injetáveis tb?
- ??? Lifecycle? Poderíamos permiter onDestroy (notificar se nao tiver escopo próprio)
Arquivo: app/concrete/components/todo.ts
import {Component, View, Inject} from 'tng';
import {Storage} from './abstract/services/storage';
@Component({
selector: 'todo'
})
@View({
controllerAs: 'todo',
template: '<div class="todo"></div>'
})
export class Todo {
private storage: Storage;
private element: ng.IJqueryElement;
constructor(@Inject('storage') storage: Storage
@Inject('element') element: ng.IJqueryElement) {
this.storage = storage;
this.element = element;
}
static link(@Inject('scope') scope: ng.IScope,
@Inject('element') element: ng.IJqueryElement) {
...
}
add() {
...
}
}
Arquivo: app/concrete/components/todo-item.ts
import {Component, View} from 'tng';
@Component({
selector: 'todo-item',
require: ['^todo']
})
@View({
controllerAs: 'item',
template: '<div class="todo-item"></div>'
})
export class TodoItem {
...
}
- Decorador:
@Decorator
- Instanciado com
$injector.instantiate()
- Tanto o construtor quanto
decorate()
recebem injeções decorate()
deve retornar o serviço decorado
import {Decorator, Inject} from 'tng';
@Decorator({
name: 'storage'
})
class StorageDecorator implements Decorator {
// Injectable
constructor() {
...
}
// Injectable
decorate(@Inject('$delegate') $delegate: any): any {
...
}
}
- Decorator:
@Animation
- Singleton
- Instanciado com
$injector.instantiate()
import {Animation} from 'tng';
@Animation({
name: 'fade'
})
class FadeAnimation implements Animation {
// Injectable
constructor() {
...
}
...
}
- Decorator:
@Filter
- Singleton
- Instanciado com
$injector.instantiate()
import {Filter, Inject} from 'tng';
@Filter({
name: 'orderBy'
})
class OrderByFilter implements Filter {
// Injectable
constructor() {
...
}
// Not injectable
filter(input: any, ...args: any[]): any {
...
}
}
TODO necessário? Acho que não...
- Anotações são herdadas quando se extende uma classe
- Pode-se extrair as anotações manualmente:
var annotations = Component.inheritsFrom(sourceClass)
- Extracts annotations made with
Component
for imperative use
- Extracts annotations made with
@Component.inheritsFrom(sourceClass)
- Extracts annotations made with
Component
and applies them to the target class
- Extracts annotations made with
Automatic inheriting annotations:
import {Component} from 'tng';
import {TodoItem} from './todo-item';
// GoldenTodoItem automaticly inherits annotations from TodoItem
// Adds new annotations do override inherited ones
@Component({
selector: 'golden-todo-item'
})
@View({
controllerAs: 'item',
template: '<div class="golden-todo-item"></div>'
})
export class GoldenTodoItem extends TodoItem {
...
}
Manualy inherting annotations:
import {Component} from 'tng';
import {TodoItem} from './todo-item';
@Component.inheritsFrom(TodoItem)
@Component({
selector: 'golden-todo-item'
})
@View({
controllerAs: 'item',
template: '<div class="golden-todo-item"></div>'
})
export class GoldenTodoItem {
...
}
import {Module} from 'tng';
import {Services} from './concrete/services';
var rawModule = Module.unwrap(Services, 'services');
rawModule.controller(...);
rawModule.service(...);
rawModule.directive(...);
index.html
<div ng-outlet="main"></div>
greetings.ts
@RouteConfig({
name: 'greetings', // state.name
path: '/greetings/:name', // state.url
outlet: 'main' // state.views = { 'main' : {controller: ...} }
})
@Component({
selector: 'greetings'
})
@View({
controllerAs: 'greetings',
template: '{{ greetings.message }}'
})
export class Greetings {
message = 'Hello, {name}!';
constructor($routeParams) {
this.message = this.message.replace('{name}', $routeParams['name']);
}
}
app.ts
import {Greetings} from './greetings.ts';
@Application({
selector: 'html',
dependencies: [Greetings]
})
export class App {
}
Acesso a /greetings/Diego
, renderiza...
<div ng-outlet="main">
<greetings>Hello, Diego!</greetings>
</div>
index.html
<div ng-outlet></div>
greetings.ts
@View
@Template({
controllerAs: 'greetings',
inline: '{{ greetings.message }}'
})
export class Greetings {
message = 'Hello, {name}!';
constructor($routeParams) {
this.message = this.message.replace('{name}', $routeParams['name']);
}
}
app.ts
import {Greetings} from './greetings.ts';
import {Dashboard} from './dashboard.ts';
import {Logout} from './dashboard.ts';
@Application({
selector: 'html',
dependencies: [Greetings]
})
@States([
{name: 'greetings', path: '/greetings/:name', component: Greetings},
// state = {name: 'greetings', url: '/greetings/:name', views: {'@' : {controller: Greetings...}}}
{name: 'logout', path: '/logout', components: {'@' : Logout}},
// state = {name: 'logout', url: '/logout', views: {'@' : {controller: Logout...}}}
{name: 'dashboard', path: '/dashboard', component: Dashboard, states: [
{name: 'config', path: '/config', component: 'config'},
{name: '', path: '', component: ''}
]}
// state = {name: 'dashboard', url: '/dashboard', views: {'@' : {controller: Dashboard...}}}
])
export class App {
}
Acesso a /greetings/Diego
, renderiza...
<div ng-outlet>
<greetings>Hello, Diego!</greetings>
</div>
- Nome da rota:
dashboard
- URL:
/dashboard
<div ng-outlet="main"></div>
import {Greetings} from './greetings';
@Route({
name: 'dashboard',
path: '/dashboard',
outlet: 'main',
components: {
content: Greetings, // Greetings é um componente
aside: 'search' // 'search' = seletor de um component
}
})
@Component({
selector: 'dashboard'
})
@View({
controllerAs: 'dashboard',
template: '<div ng-outlet="content"></div><div ng-outlet="aside"></div>'
})
class Dashboard {
message = 'Hello, {name}!';
constructor($routeParams) {
this.message = this.message.replace('{name}', $routeParams['name']);
}
}
Acesso a /dashboard
, renderiza...
<div ng-outlet="main">
<dashboard>
<div ng-outlet="content">
<greetings>Hello, Diego!</greetings>
</div>
<div ng-outlet="aside">
<search></search>
</div>
</dashboard>
</div>