Michael
Michael

Reputation: 22957

reuse controllers, views and services in angular app

I want my app to fetch data from a server API, lets say I have the following API /orders , /users. Basically I just want to display the json I get from the server in a table. I am using ng-table directive for that purpose. So, in terms of components I have :

  1. Services - both services do the same thing - go to an API and fetch JSON
  2. Views - same view for both of the APIs, just display different data
  3. Controllers - both fetch data from the service and display it in the table view.

So the way I see it, they all do the same thing with very minor adjustments. What I would like to do is

angular.module('admin').config(function ($routeProvider, $locationProvider) {
  // same template and controller for both
  $routeProvider.
    when('/users', {
      templateUrl: '/partials/table.html',
      controllers: '/js/controllers/table.js
    }).
    when('/orders', {
      templateUrl: '/partials/table.html',
      controllers: '/js/controllers/table.js'
    });
});

And in my service

factory('AdminService', ['$resource', function($resource) {
  // somehow I want to inject the right endpoint, depending on the route
  return $resource( '/:endpoint',
    { }, {} );
}]);

And in my table controller as well, I want to be able to know what to pass to the service

I could of course use separate controllers and services for each API endpoint it just seems like a wasteful duplication of code that does 99% the same thing

Is this possible ?

How do I wire everything together ?

Upvotes: 2

Views: 1136

Answers (1)

Michal Charemza
Michal Charemza

Reputation: 27022

If you want separate routes, but the same controller, but with some options, you can use the resolve option in the route definition to pass some options:

$routeProvider.
when('/users', {
  templateUrl: '/partials/table.html',
  controller: 'TableController',
  resolve: {
     'option1': function() {
        return 'val1'
     },
     'option2': function() {
        return 'val2'
     }
  }
}).
when('/orders', {
  templateUrl: '/partials/table.html',
  controller: 'TableController',
  resolve: {
     'option1': function() {
        return 'val3'
     },
     'option2': function() {
        return 'val4'
     }
  }
});  

Then the controller in both cases will be injected with "option1" and "option2", which can be used to customise its behaviour:

app.controller('TableController', function($scope, option1, option2) {
  // Do something with option1 or option1
});

From the resolve object functions, you could return a $resource object, or even return a promise that will be resolved with some data before the route is displayed. You can see the docs for $routeProvider for details.

Edit: For the resource, you could write a configurable factory like:

app.factory('MyResource', function($resource) {
  return function(endpoint) {
    return $resource('/' + endpoint);
  }
});

And then use it in the controller:

app.controller('TableController', function($scope, MyResource, endpoint) {
  var currentResource = MyResource(endpoint);
  currentResource.query(); // Whatever you want to do with the $resource;
}

assuming that "endpoint" was was one of the options added in the resolve, so something like

when('/orders', {
  templateUrl: '/partials/table.html',
  controller: 'TableController',
  resolve: {
     'endpoint': function() {
        return '/orders'
     }

Upvotes: 5

Related Questions