Tenho pensado muito em serviços de dados e é a única parte do Angular que me incomoda. Desde então, percebi que isso só me incomoda porque o Angular não dita nem sugere realmente como você deve gerenciar seus serviços de dados. Então, estou sempre me questionando e me perguntando “estou fazendo isso certo?” Claro que a resposta é: se funciona para você, então está certo, porque o Angular não se importa. Isso funcionou até agora, mas gerou um código confuso que era difícil de transferir para outros projetos. Então voltamos para a prancheta.
Depois de ler vários posts e assistir a vídeos sobre modelagem de dados avançada no Angular, ainda achei que muitas das soluções eram um pouco complicadas. Não estou convencido de que estamos certos ainda, mas sugerimos o seguinte, que funciona bem para nossas necessidades e parece ser uma abordagem bastante decente, o que não é muito incompreensível. Eu queria publicar um código aqui para ajudar qualquer pessoa que está se sentindo da mesma forma que eu sobre o problema e para obter feedback.
services.js
Este é o serviço de base que iremos utilizar. Isso nos permite incluir um módulo em nosso aplicativo para incluir todos os serviços necessários para interagir com a API Mallzee. O legal disso é que nos permite criar chamadas de API para cada serviço que o estende e mantém grande parte do nosso código DRY.
Podemos criar muitas chamadas comuns aqui, como fetch, fetchOne, query, etc. O principal driver por trás dessa abordagem era porque estávamos nos repetindo escrevendo código de mesclagem de cache em nossos serviços. Queremos a capacidade de extrair nossos dados de LocalStorage primeiro, fazer uma solicitação para os dados ativos e atualizar quaisquer alterações. Mais sobre isso em outro post. Essa técnica nos permite fazer isso uma vez em nossas chamadas comuns.
Também criamos um provedor para que este serviço e seu uso de restangular possam ser acoplados a outros serviços sem causar problemas com URLs de base e similares.
angular.module('mallzee.services', [
'restangular',
'mallzee.services.brands',
'mallzee.services.products'
]).provider('MallzeeService', function MallzeeServiceProvider() {
var baseUrl = 'https://api.mallzee.com';
var scope = this;
this.$get = ['MallzeeRestangular', function (MallzeeRestangular) {
MallzeeRestangular.setBaseUrl(baseUrl);
var MallzeeService = function () { };
MallzeeService.prototype = {
scope: this,
initialise: function () {
scope = this;
if (scope.key) {
this[scope.key] = [];
}
if (scope.key && scope.model) {
// Extend any objects sourced from Local Storage
angular.forEach(scope[scope.key], function (obj) {
angular.extend(obj, scope.model);
});
// Extend any future objects we retrieve with Restangular
MallzeeRestangular.extendModel(scope.key, function (model) {
return angular.extend(model, scope.model);
});
}
},
fetch: function () {
scope = this;
MallzeeRestangular.all(scope.key).getList().then(function (data) {
angular.extend(scope[scope.key], data);
});
},
fetchOne: function() {} // Removed to keep things short
query: function () {} // Removed to keep things short
};
return {
getInstance: function () {
return new MallzeeService();
}
}
}];
this.setBaseUrl = function (url) {
baseUrl = url;
};
}).factory('MallzeeRestangular', ['Restangular', function (Restangular) {
return Restangular.withConfig(function(RestangularConfigurator) {
// Configure the version of Restangular used for this API
// i.e. set headers, object transforms etc
});
}]);
services / marks.js
Quando criamos nosso serviço, apenas injetamos nosso serviço de baseMallzeeService
e estendemos uma instância dele para nos fornecer uma API específica de serviço.
Aproveitamos a fábrica para dar aos itens devolvidos uma estrutura tipo modelo, este é um lugar perfeito para colocar a lógica do negócio e mantê-la nossa dos controladores.
angular.module('mallzee.services.brands', [])
// This will act as the model for each brand item received from the API
.factory('Brand', [function () {
return {
toggle: function () {
this.enabled = !this.enabled;
return this.enabled;
}
// Add model specific API function here
};
}])
.factory('BrandsService', ['MallzeeService', 'Brand', function (MallzeeService, Brand) {
var brandsService = angular.extend(MallzeeService.getInstance(), {
key: 'brands',
model: Brand
// Add any specific collection API functions to this object
});
brandsService.initialise();
return brandsService;
}]);
controladores / marcas.js
Podemos então usar isso de forma muito simples em nossos controladores.
angular.module('mallzee.controllers.brands', [])
.controller('BrandCtrl', [
'$scope',
'BrandsService',
function ($scope, $state, BrandsService) {
$scope.brands = BrandsService.brands;
$scope.$on('$viewContentLoaded', function (event, view) {
if (view.stateName === 'brands') {
BrandsService.fetch();
}
});
}]);
app.js
Por fim, apenas incluímos o serviço de nível superior e o configuramos se quisermos apontar para uma URL diferente, digamos durante o desenvolvimento, ou qualquer outra coisa.
angular.module('mallzee', [
'mallzee.services'
).config(['MallzeeServiceProvider', function (MallzeeServiceProvider) {
MallzeeServiceProvider.setBaseUrl('https://dev.mallzee.com');
});
Estou gostando disso porque devemos ser capazes de despejar isso em qualquer projeto angular agora e estar confortáveis, pois nossas interações permanecerão estáveis ao falar com a API. Também está configurado para funcionar bem com nosso sistema de cache e armazenamento local.
Eu adoraria ouvir a opinião das pessoas sobre isso.