Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular multiple routes sharing one controller

I'm not sure if I'm approaching this correctly but I'm building an ecommerce site - part of the site has 6 different product grid pages, each of which can use the same view:

<ul class="products row">
    <li class="product thumbnail col-1 grid" ng-repeat="whisky in whiskies | orderBy: sort">
        <p class="picture">
            <a ng-href="#/json/{{whisky.id}}"><img ng-src="images/scotch/{{whisky.imageUrl}}" alt="{{whisky.name}}"/></a>
        </p>
        <div class="desc">
            <h2>{{whisky.name}}</h2>
            <p class="price"><span>&pound;{{whisky.price}}</span></p>
        </div>
        <div class="actions">    
        <button class="add-to-basket btn btn-primary btn-medium fa fa-shopping-cart" data-item='{"imageUrl" : "{{whisky.imageUrl}}", "price" : "{{whisky.price}}", "startPrice" : "{{whisky.price}}", "name" : "{{whisky.name}}", "totalItems" : "{{1}}"}' ng-click="updateMiniBasket($event)"></button>    
        </div>
    </li>
</ul>

and the same controller:

whiskyControllers.controller('whiskyListCtrlr', ['$scope', 'whiskyList', '$http', 

    function($scope, whiskyList, $http){

        whiskyList.getWhiskies().then(function(d) {
            $scope.whiskies = d.data;
        })

    }

])

but need to have a different route in the route provider config i.e. one goes to scotch, one goes to irish, one to japanese etc.

How do I code the routing so that the different pages share the same controller and view? Is it maybe possible to pass parameters from the router to the controller?

Many thanks

like image 843
Mike Alizade Avatar asked Sep 15 '25 08:09

Mike Alizade


2 Answers

Yes, you can reuse controllers and views as often as you want. If I understand you correctly, you want different routes to use the same controller and view? That's easy. Additionally, you want to be able to pass variables to your controller when the route is triggered? Also easy. Here is an example that does not use ui-router.

angular.module('myApp').config(['$routeProvider', 'whiskeyList', appConfig]); 

function appConfig($routeProvider, wiskeyList) {
  $routeProvider
  .when('/scotch', {
    controller: 'whiskeyListCtrlr',
    resolve: {
      data: function(whiskeyList) {
        return whiskeyList.getWhiskeys();
      }
    }
  })
  .when('/irish', {
    controller: 'whiskeyListCtrlr',
    resolve: {
      data: function(whiskeyList) {
        return whiskeyList.getWhiskeys();
      }
    }
  });
}

Obviously, this implementation is not DRY (Don't Repeat Yourself). I would rethink your implementation. I would change whiskeyList.getWhiskeys() to accept a parameter that tells it the type of whiskey to return. For example, whiskeyList.getWhiskeys('scotch'). Then, the data you receive in your controller is filtered to only what the view requires.

The data mapped in the router's resolve function is accessed in the controller by name.

whiskyControllers.controller('whiskyListCtrlr', ['$scope', 'data', function ($scope, data) {
  $scope.whiskeys = data;
});
like image 53
Brett Avatar answered Sep 17 '25 05:09

Brett


This is pretty easy to do with ui-router, which offers many advantages over the built in routing in angular. Ui Router allows you to encapsulate states by specifying a template and controller, and "resolve" data (based off of route or other parameters) which you can then pass into your controllers. Something like the following would work well for you:

angular.module('whiskyApp')
    .config(['$stateProvider', function($stateProvider) {
        $stateProvider
        .state('whiskyList', {

             // whisky-type is a catch all here - can be 'irish', 'japanese', anything.
             // can also use regex to restrict it a bit
             url: '/lists/:whiskyType',
             templateUrl: 'whisky-list-template.html',
             controller: 'whiskyListCtrl',

             // this is what gets passed to the controller
             resolve: {
                 type: ['$stateParams', function($stateParams) {

                     // pass the whisky type from the url into the controller
                     return $stateParams.whiskyType;
                 }],
                 list: ['$stateParams', 'whiskyList', function($stateParams, whiskyList) {

                     // we can also go ahead and pass in the resolved list - this is best practice
                     return whiskyList.getWhiskies();
                 }]
             }
        });
    }]);

]);

And then in your contoller, just inject the name of keys of the 'resolve' map to use them:

whiskyControllers.controller('whiskyListCtrlr', ['$scope', 'list', 'type' '$http', 

    function($scope, list, type, $http){
       $scope.whiskies = list;
       $scope.type = type;
    }
])
like image 35
javamonn Avatar answered Sep 17 '25 06:09

javamonn