AngularJs Done Right!
by Rafael Violato
Assuntos
- Services
- Dependency Injection
- Fat Model, skinny Controller
- Promises e $q
Services
Services, Factories e Providers
Service
- Um service é uma função construtora
- Por trás dos panos é feito um new nesta função
- Você recebe uma nova e única instância
- Semelhantes a classe do ES6
angular.module('awesomeApp')
.service('myService', service);
function service(){
this.something = 'something';
this.sum = sum;
function sum(a, b) {
return a + b;
}
}
Factory
- Você recebe a referência da função
- A função é executada, e o que é injetado é o que foi retornado
- Por isso permite maior nível de configuração (código antes do return)
- Possibilidade de criar quantas instâncias desejar
angular.module('awesomeApp')
.factory('myFactory', factory);
function factory(){
var something = 'something';
var factory = {
something: something,
sum: sum
};
return factory;
function sum(a, b) {
return a + b;
}
}
Provider
- Service com maior nível de configuração
- Requer que exponha-se uma função $get que funcionará como service
- Permite configuração na fase de config do módulo através de métodos e variáveis fora do $get
- $get funciona como um factory
angular.module('myApp')
.provider('myProvider', provider);
function provider() {
this.configVar = 'This is a config var';
this.$get = $get;
function $get() {
var serviceVar = 'This is a service var';
var factory = {
serviceVar: serviceVar
};
return factory;
}
}
Como funciona?
- Quando você declara uma estrutura injetável, o $provide é chamado no config do seu módulo
- Cada estrutura definida (Ex.: .service(...), .factory(...), etc...) são atalhos para chamadas dos métodos respectivos no $provide
- O $inject é o resposável de injetar estes services em qualquer função ou estrutura de dado
- $inject.get() busca pelo service e devolve a função
- $inject.invoke() é responsável por deixar o service disponível em qualquer função
- O angular utiliza um invoke para cada requisição de injeção
Fat Model, skinny Controller
Que porra é essa?
- Fazer teu model em Services
- Controller recebe as injeções de model
- Abstrair toda lógica para o model
- Goodbye $scope!
Vantagens
- Possui um model somente pelo pattern singleton dos services
- Menos copy/paste
- "Métodos Globais"
- Mais simples de testar
- Injeta o model em qualquer estrutura
- Independe da hierarquia de $scope
- Somente uma "fonte da verdade"
- Mais próximo do Angular 2
$http
- É um service do Angular
- Retorna uma promise
- Tradicionalmente é um GET porém aceita todos os comandos comums de http request (ex.: PUT, DELETE, etc...)
- Métodos para tratar promise: then, catch, success, error e finally
angular.module('awesomeApp')
.factory('myService', service);
service.$inject = ['$http'];
function service($http){
var service = {
getData: getData
};
return service;
function getData() {
return $http('http://api.pagar.me/1/transactions');
}
}
$q
- Promises customizáveis
- Formato semelhante a promise do ES6
angular.module('awesomeApp')
.service('myService', service);
service.$inject = ['$q', '$timeout'];
function service($q, $timeout) {
var self = this;
this.wait = wait;
this.done = false;
function wait() {
var promise = $q(function(resolve, reject) {
$timeout(resolve, 1000);
});
promise.then(success, error);
}
function success() {
self.done = true;
}
function error() {
self.done = false;
}
}
controllerAs
- Consegue utilizar a função do controller como model
- Convenção: var vm = this;
- Desta forma o conseguimos de vez deixar o $scope de lado como model
- Pode estabelecer o namespace no controllerAs na rota ou na diretiva ng-controller
Mas pra quê?!
- Adiciona um namespace aos dados
- Favorece leitura do código
- Resolve problema de nested controllers
- Abandona $scope
angular.module('awesomeApp')
.controller('myController', controller);
controller.$inject = ['myService'];
function controller(myService){
var vm = this;
myService.getData()
.then(success, error);
function success(promiseData) {
vm.data = promiseData;
}
function error() {
console.error('Oh Fuck!');
}
}
<div ng-controller="myController as ctrl">
<ul>
<li ng-repeat="item in ctrl.data"></li>
</ul>
</div>
Bora juntar o que aprendemos
Como utilizar estes conceitos juntos?
- Utilize providers para services com pré configuração
- Concentre toda sua lógica no model (services)
- Para dados assíncronos, utilize promises nos models
- Injete o model em qualquer estrutura que necessitar dele
- Através do controllerAs, exponha os dados para a view
- Utilize $scope somente para $watchers, $scope events e alguns métodos específicos ($apply, $parse, $eval, etc...)
Para estudar
Criar aplicações utilizando fat-model skinny-controller
https://scotch.io/tutorials/making-skinny-angularjs-controllers
Styleguides John Papa e Todd Motto
http://nomadev.com.br/angularjs-promises-promessas-o-guia-definitivo/
https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
AngularJs Done Right!
by Rafael Violato