20

I currently have an AngularJS app with routing built in and it works perfectly with static controller property assignments. but what I really want to do is to dynamically assign controllers with different routes:

$routeProvider
 .when("/Dashboards/:dashboardName",{
    templateUrl:function(params) {
                 return "Dashboards/" + params.dashboardName;
                //some ASP.NET MVC calls to return partial views (this part works)
        }
  })

What I would like to do is to do the same thing about my controller property here, like:

$routeProvider
 .when("/Dashboards/:dashboardName",{
       templateUrl:function(params) {
             return "Dashboards/" + params.dashboardName;
            //some ASP.NET MVC calls to return partial views (this part works)
           },
       controller: function(params) {
             return params.dashboardName+"Controller"; (this part DOESN'T work)
           }
  })

but as it seems I am get an error saying paramsProvider is not found

so is there any way I could dynamically load my controller function name in route configuration?

BKM
  • 6,949
  • 7
  • 30
  • 45
Kia Panahi Rad
  • 1,235
  • 2
  • 11
  • 22

5 Answers5

11

This is possible to do using angular ui-router.

The ui-router lets you specify a "controllerProvider" to specify a function for providing a controller. So the solution would look like this:

$stateProvider
.state("/Dashboards/:dashboardName",{
   templateUrl:function($stateParams) {
         return "Dashboards/" + $stateParams.dashboardName;
       },
   controllerProvider: function($stateParams) {
         return $stateParams.dashboardName+"Controller";
       }
  })

I hope it helps!

Bradley Trager
  • 3,570
  • 3
  • 26
  • 33
  • ah, I reread the question and understand what was being asked (and removed my answer). Your solution will work to dynamically determine the controller's name, but the controller would still need to be fetched and loaded from the server dynamically which doesn't appear to be part of the question, but an FYI for future readers. – TheSharpieOne Jan 07 '14 at 20:37
7

I solved this issue by not specifying the controller in $routeProvider but instead placing it in the file specified in templateURL.

$routeProvider
 .when("/Dashboards/:dashboardName",{
    templateUrl:function(params) {
                 return "Dashboards/" + params.dashboardName;
        }
  })

In DashboardsNAME.html

<div class="container" ng-Controller='DashboardsNAMEController'>Food</div>

This technique still requires that at some point before the route is instantiated you have registered DashboardsNAMEController. I suspect that the best place to do it is in the module.run() method with call to your own service but I do it in my main controller because it works and is a short controller anyway.

Nathaniel Johnson
  • 4,731
  • 1
  • 42
  • 69
  • This works, but I do not understand why the other way does not work. – Bradley Trager Jan 07 '14 at 19:05
  • @BradleyTrager Which other one? – Nathaniel Johnson Jan 07 '14 at 19:10
  • The one in the question where the controller is specified in a function on the route provider. – Bradley Trager Jan 07 '14 at 19:16
  • 1
    He is linking a function that will act as a controller to the route. The routeParams are not available to that controller. If he wants the controller to be `params.dashboardName+"Controller"` he needs to turn that line into an expression like : `controller: params.dashboardName+"Controller"` and not wrap it in a function. – Nathaniel Johnson Jan 07 '14 at 19:24
  • Thank you, I get it now! Now I am just wondering how to get the "params" without wrapping it in a function. – Bradley Trager Jan 07 '14 at 19:28
  • Take a look at @Benjamin Oman's answer on dynamic controllers. Also, this issue is the reason I submitted: https://github.com/angular/angular.js/issues/5410 Put a +1 in comments if you like it. – Nathaniel Johnson Jan 07 '14 at 19:44
4

I have been attempting this same thing. One solution I've found is to do this inside your routeProvider:

 $routeProvider
    .when("/Dashboards/:dashboardName",{
        templateUrl:function(params) {
            return "Dashboards/" + params.dashboardName;
        },
        controller: 'dynamicController'
 });

And then you do your calculation for what "pseudo-controller" (for lack of a better name) to load inside of the "dynamicController" definition.

var controllers = {
    unoController: function($scope, $routeParams, $rootScope) {
        // Do whatever
    },
    dosController: function($scope, $routeParams, $rootScope) {
        // Whatever for this controller
    }
}

app.controller('dynamicController', ['$scope', '$routeParams', '$rootScope', function($scope, $routeParams, $rootScope) {
    controllers[$routeParams.dashboardName+"Controller"]($scope, $routeParams, $rootScope);
}]);

This assumes that $routeParams.dashboardName is one of ["uno","dos"].

Take this with a grain of salt as I've only had about 3 days with Angular, but so far this approach has worked great for what I'm trying to accomplish.

Benjamin Oman
  • 1,654
  • 1
  • 17
  • 19
4

I don't know if it depends on AngularJS version but you can serve a function to the controller property, the function becoming the actual controller. Using this fact in conjunction with controller inheritance you can obtain a more condensed code like the one you were looking for, I think:

$routeProvider
.when("/Dashboards/:dashboardName",{
    templateUrl:function(params) {
        return "Dashboards/" + params.dashboardName;
    },
    controller: function($scope, $routeParams, $controller) {
        /* this creates a child controller which, 
           if served as it is, should accomplish 
           your goal behaving as the actual controller
           (params.dashboardName + "Controller") */
        $controller($routeParams.dashboardName + "Controller", {$scope:$scope});
    }
})

Disclaimer: I honestly don't know if this approach has any drawbacks. Doesn't look so though.

Community
  • 1
  • 1
mettjus
  • 2,938
  • 4
  • 24
  • 32
0

Here is something that also works, (at least for me). This may help future people searching for answer.

$stateProvider
    .state('foo', {
        url: '/foo/:bar',
        templateUrl: 'some-template-path.html',
        resolve : {
            getController : function($stateParams){
                if ($stateParams.bar === "tab1") {

                    return "tab1Controller"

                }else if ($stateParams.bar === "tab2") {

                    return "tab2Controller"

                }else if ($stateParams.bar === "tab3"){

                    return "tab3Controller"

                }else if ($stateParams.bar === "tab4") {

                    return "tab4Controller"

                }
            }
        },
        controllerProvider: function(getController){
            return getController;
        },

Not the shortest code but at least easier to read. Also if you want to give the controller a different name from the tab/dashboardName name.

jofftiquez
  • 7,548
  • 10
  • 67
  • 121