Modelos Ricos com AngularJS

William Grasel

Por que?

Real Apps:

Triste Realidade: CRUD

O Problema não é novo

... mas não é o foco do AngularJS

Classic Angular Way

  angular.module('myApp', ['restangular'])
  .controller('MyCtrl', function(Restangular) {
    // GET /proposals/1
    this.model = Restangular.all('proposals').get(1).$object;

    this.profit = function() { ... };
    this.revenue = function() { ... };
  });
<form ng-app="myApp" ng-controller="MyCtrl as ctrl" novalidate>

  <input type="text" ng-model="ctrl.model.cost" required>

  <label ng-bind="ctrl.profit()"></label>

  <label ng-bind="ctrl.revenue()"></label>

</form>

Primeiro Passo:

Isole e Teste seu Modelo

  angular.module('models')
  .factory('Proposal', function() {
    return {
      profit: function() { ... },
      revenue: function() { ... },
      ...
      validation: function() { ... }
    };
  });

Segundo Passo:

Conecte com sua infra

  angular.module('services', ['restangular', 'models'])
  .factory('ProposalSvc', function(Restangular, Proposal){

    Restangular.extendModel('proposals', function(model) {
      return angular.extend(model, Proposal);
    });
 
    return Restangular.all('proposals');
  });

Terceiro Passo:

Use e Reutilize

  angular.module('myApp', ['services'])
  .controller('MyCtrl', function(ProposalSvc) {
    // GET /proposals/1
    this.model = ProposalSvc.get(1).$object;
  });
<form ng-app="myApp" ng-controller="MyCtrl as ctrl" novalidate>

  <input type="text" ng-model="ctrl.model.cost" sua-magica-que-exibe-validacoes>

  <label ng-bind="ctrl.model.profit()"></label>

  <label ng-bind="ctrl.model.revenue()"></label>

</form>

Nested Models

Primeira abordagem

  angular.module('services', ['restangular', 'models'])
  .factory('ProposalSvc',
  function(Restangular, Proposal, User, Address, Currency){

    Restangular.extendModel('proposals', function(model) {
      angular.extend(model.internalCurrency, Currency);
      angular.extend(model.externalCurrency, Currency);
      angular.extend(model.user, User);
      angular.extend(model.user.address, Address);

      return angular.extend(model, Proposal);
    });
 
    return Restangular.all('proposals');
  });

Nested Models

Segunda abordagem

  .factory('ProposalSvc', function(Restangular, Proposal){
    Restangular.extendModel('proposals', function(model) {
      return Proposal.mixInto(model);
    });
    ...
  });
.factory('Proposal', function(User, Currency) {
  return {
    ...
    mixInto: function(model) {
      User.mixInto(model.user);
      Currency.mixInto(model.internalCurrency);
      Currency.mixInto(model.externalCurrency);
      return angular.extend(model, this);
    }
  };
});
.factory('User', function(Address) {
  return {
    ...
    mixInto: function(model) {
      Address.mixInto(model.address);
      return angular.extend(model, this);
    }
  };
});

Event Listeners?

Dúvidas? Comentários?

Obrigado!