AngularAMD + ui-router + dynamic controller name?

前端 未结 1 660
广开言路
广开言路 2020-11-27 06:43

I\'m trying to write a generalized route in my application and resolve the view and controller names on the fly based on the route params.

I have the following code

相关标签:
1条回答
  • 2020-11-27 07:06

    This is a link to working plunker.

    solution

    We need two features of the UI-Router:

    • resolve (to load the missing pieces of js code)
    • controllerProvider (see cites from documentation below)

    angularAMD - main.js definition

    This would be our main.js, which contains smart conversion controllerName - controllerPath:

    require.config({
    
        //baseUrl: "js/scripts",
        baseUrl: "",
    
        // alias libraries paths
        paths: {
            "angular": "angular",
            "ui-router": "angular-ui-router",
            "angularAMD": "angularAMD",
    
            "DefaultCtrl": "Controller_Default",
            "OtherCtrl": "Controller_Other",
        },
    
        shim: {
            "angularAMD": ["angular"],
            "ui-router": ["angular"],
        },
    
        deps: ['app']
    });
    

    controllers:

    // Controller_Default.js
    define(['app'], function (app) {
        app.controller('DefaultCtrl', function ($scope) {
            $scope.title = "from default"; 
        });
    }); 
    
    // Controller_Other.js
    define(['app'], function (app) {
        app.controller('OtherCtrl', function ($scope) {
            $scope.title = "from other";
        });
    });
    

    app.js

    Firstly we would need some method converting the param (e.g. id) into controller name. For our test purposes let's use this naive implementation:

    var controllerNameByParams = function($stateParams)
    {
        // naive example of dynamic controller name mining
        // from incoming state params
    
        var controller = "OtherCtrl";
    
        if ($stateParams.id === 1) {
            controller = "DefaultCtrl";
        }
    
        return controller;
    }
    

    .state()

    And that would be finally our state definition

    $stateProvider
        .state("default", angularAMD.route({
            url: "/{id:int}",
            templateProvider: function($stateParams)
            {
                if ($stateParams.id === 1)
                {
                    return "<div>ONE - Hallo {{title}}</div>";
                }
                return "<div>TWO - Hallo {{title}}</div>";
            },
            resolve: {
                loadController: ['$q', '$stateParams',
                    function ($q, $stateParams)
                    {
                        // get the controller name === here as a path to Controller_Name.js
                        // which is set in main.js path {}
                        var controllerName = controllerNameByParams($stateParams);
    
                        var deferred = $q.defer();
                        require([controllerName], function () { deferred.resolve(); });
                        return deferred.promise;
                    }]
            },
            controllerProvider: function ($stateParams)
            {
                // get the controller name === here as a dynamic controller Name
                var controllerName = controllerNameByParams($stateParams);
                return controllerName;
            },
        }));
    

    Check it here, in this working example

    documentation

    As documented here: $stateProvider, for a state(name, stateConfig) we can use controller and controllerProvider. Some extract from documentation:

    controllerProvider

    ...

    controller (optional) stringfunction

    Controller fn that should be associated with newly related scope or the name of a registered controller if passed as a string. Optionally, the ControllerAs may be declared here.

    controller: "MyRegisteredController"
    
    controller:
    "MyRegisteredController as fooCtrl"}
    
    controller: function($scope, MyService) {
    $scope.data = MyService.getData(); }
    

    controllerProvider (optional) function

    Injectable provider function that returns the actual controller or string.

    controllerProvider:
      function(MyResolveData) {
        if (MyResolveData.foo)
          return "FooCtrl"
        else if (MyResolveData.bar)
          return "BarCtrl";
        else return function($scope) {
          $scope.baz = "Qux";
        }
      }
    

    ...

    resolve

    resolve (optional) object

    An optional map<string, function> of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them ALL to be resolved before the controller is instantiated...

    I.e. let's use controllerProvider:

    ... to resolve the controller name dynamically...

    In case, that you managed to get here, maybe you'd like to check another similar solution with RequireJS - angular-ui-router with requirejs, lazy loading of controller

    0 讨论(0)
提交回复
热议问题