Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 角度ui路由器将值解析为字符串_Javascript_Angularjs_Angular Ui Router_Angularjs Routing_Angularjs Controller - Fatal编程技术网

Javascript 角度ui路由器将值解析为字符串

Javascript 角度ui路由器将值解析为字符串,javascript,angularjs,angular-ui-router,angularjs-routing,angularjs-controller,Javascript,Angularjs,Angular Ui Router,Angularjs Routing,Angularjs Controller,使用ui路由器,我在状态函数中添加了所有解析逻辑,如下所示 //my-ctrl.js var MyCtrl = function($scope, customers) { $scope.customers = customers; } //routing.js $stateProvider.state('customers.show', { url: '/customers/:id', template: templa

使用ui路由器,我在状态函数中添加了所有解析逻辑,如下所示

    //my-ctrl.js
    var MyCtrl = function($scope, customers) {
      $scope.customers = customers;
    }

    //routing.js
    $stateProvider.state('customers.show', {
      url: '/customers/:id',
      template: template,
      controller: 'MyCtrl',
      resolve: {   // <-- I feel this must define as like controller
        customers: function(Customer, $stateParams) {
          return Customer.get($stateParams.id);
        }
      }
    });
但是,当我将其定义为
MyCtrl.resolve
时,由于IIFE,我得到了以下错误

Failed to instantiate module due to: ReferenceError: MyCtrl is not defined
当我将它定义为string
'MyCtrl.resolve'
时,我得到

Error: 'invocables' must be an object.
我看到控制器被定义为string,所以我认为也可以通过使用decorator或其他东西来提供string值


有人用过这种方法吗?这样我就可以保持routings.js的整洁,并放置相关信息。在一个相关的文件中?

这听起来是一个构建解析的好方法,但我认为你做不到

除了“解析”需要一个对象这一事实之外,它是在一个阶段定义的,在这个阶段中,所有可用的都是提供者。此时,控制器甚至还不存在

然而,更糟糕的是,“解析”意味着定义控制器本身的输入。要在控制器中定义解析,然后期望在创建控制器之前对其进行评估,这是一个循环依赖项

过去,我在
$stateProvider
定义之外定义了解析函数,至少允许重用它们。我从来没有试过找比这更喜欢的人

var customerResolve = ['Customer', '$stateParams',
    function(Customer, $stateParams) {
        return Customer.get($stateParams.id);
    }
];

// ....

$stateProvider.state('customers.show', {
  url: '/customers/:id',
  template: template,
  controller: 'MyCtrl',
  resolve: {
    customers: customerResolve
  }
});

您需要确保控制器与状态配置在同一个闭包中。这并不意味着它们需要在同一个文件中定义

因此,不要使用字符串,而是使用控制器的静态属性:

resolve: MyCtrl.resolve,
更新

然后,对于控制器文件:

var MyCtrl;
(function(MyCtrl, yourModule) {

    MyCtrl = function() { // your contructor function}
    MyCtrl.resolve = { // your resolve object }

    yourModule.controller('MyCtrl', MyCtrl);

})(MyCtrl, yourModule)
(function(MyCtrl, yourModule) {

    configStates.$inject = ['$stateProvider'];
    function configStates($stateProvider) {

        // state config has access to MyCtrl.resolve
        $stateProvider.state('customers.show', {
            url: '/customers/:id',
            template: template,
            controller: 'MyCtrl',
            resolve: MyCtrl.resolve
        });
    }

    yourModule.config(configStates);

})(MyCtrl, yourModule);
然后,当您在另一个文件中定义状态时,该文件在控制器文件之后包含、连接或必需:

var MyCtrl;
(function(MyCtrl, yourModule) {

    MyCtrl = function() { // your contructor function}
    MyCtrl.resolve = { // your resolve object }

    yourModule.controller('MyCtrl', MyCtrl);

})(MyCtrl, yourModule)
(function(MyCtrl, yourModule) {

    configStates.$inject = ['$stateProvider'];
    function configStates($stateProvider) {

        // state config has access to MyCtrl.resolve
        $stateProvider.state('customers.show', {
            url: '/customers/:id',
            template: template,
            controller: 'MyCtrl',
            resolve: MyCtrl.resolve
        });
    }

    yourModule.config(configStates);

})(MyCtrl, yourModule);

对于生产代码,您仍然希望将所有这些IIFE包装到另一个IIFE中。大口喝或咕噜可以帮你

这个问题是关于ui路由器包的特性。默认情况下,ui路由器不支持resolve参数的字符串。但是如果你看一下ui路由器的源代码,你会发现,不直接修改代码就可以实现这个功能

现在,我将展示建议方法背后的逻辑及其实现

分析代码 首先,我们来看看$STATE.TIVATION函数角UI路由器/SRC/urLouTr.js。在该函数中,我们将看到以下代码

  for (var l = keep; l < toPath.length; l++, state = toPath[l]) {
    locals = toLocals[l] = inherit(locals);
    resolved = resolveState(state, toParams, state === to, resolved, locals, options);
  }
这是检索解析参数承诺的具体位置。什么是好的使用,功能,这是采取了一个单独的服务。这意味着我们可以通过decorator钩住并改变它的行为

为了便于参考,$resolve的实现在angular ui router/src/resolve.js文件中

实现钩子 $resolve的resolve函数的签名为

this.resolve = function (invocables, locals, parent, self) {
其中“invocables”是我们国家声明的对象。所以我们需要检查“invocales”是否是字符串。如果是,我们将通过字符串获得控制器函数,并在“.”字符后调用函数

//1.1 Main hook for $resolve
$provide.decorator('$resolve', ['$delegate', '$window', function ($delegate, $window){ 
  var service = $delegate; 



  var oldResolve = service.resolve;
  service.resolve = function(invocables, locals, parent, self){
     if (typeof(invocables) == 'string') {
       var resolveStrs = invocables.split('.');

       var controllerName = resolveStrs[0];
       var methodName = resolveStrs[1];

       //By default the $controller service saves controller functions on window objec
       var controllerFunc = $window[controllerName];
       var controllerResolveObj = controllerFunc[methodName]();

       return oldResolve.apply(this, [controllerResolveObj, locals, parent, self]);

     } else {
       return oldResolve.apply(this, [invocables, locals, parent, self]);
     }
  };

  return $delegate;
}]);
编辑: 您还可以使用提供程序覆盖$controllerProvider,如下所示:

app.provider("$controller", function () {

}
这样就可以添加一个新函数getConstructor,它将按名称返回控制器构造函数。因此,您将避免在挂钩中使用$window对象:

$provide.decorator('$resolve', ['$delegate', function ($delegate){ 
    var service = $delegate; 

    var oldResolve = service.resolve;
    service.resolve = function(invocables, locals, parent, self){
       if (typeof(invocables) == 'string') {
         var resolveStrs = invocables.split('.');

         var controllerName = resolveStrs[0];
         var methodName = resolveStrs[1];

         var controllerFunc = $controllerProvider.getConstructor(controllerName);
         var controllerResolveObj = controllerFunc[methodName]();

         return oldResolve.apply(this, [controllerResolveObj, locals, parent, self]);

       } else {
         return oldResolve.apply(this, [invocables, locals, parent, self]);
       }
    }; 

演示此方法的完整代码

如果打算将冲突解决程序与控制器放在同一个文件中,最简单的方法是在控制器文件中将冲突解决程序声明为函数:

//my-ctrl.js
var MyCtrl = function($scope, customers) {
  $scope.customers = customers;
}
var resolverMyCtrl_customers = (['Customer','$stateParams', function(Customer, $stateParams) {
    return Customer.get($stateParams.id);
}]);

//routing.js
$stateProvider.state('customers.show', {
  url: '/customers/:id',
  template: template,
  controller: 'MyCtrl',
  resolve: resolverMyCtrl_customers
});
这应该行得通

//my-ctrl.js
var MyCtrl = function($scope, customer) {
    $scope.customer = customer;
};

//routing.js
$stateProvider
    .state('customers.show', {
        url: '/customers/:id',
        template: template,
        resolve: { 
            customer: function(CustomerService, $stateParams){
                return CustomerService.get($stateParams.id)
            } 
        },
        controller: 'MyCtrl'
});


//service.js
function CustomerService() {
    var _customers = {};

    this.get = function (id) {
        return _customers[id];
    };
}

配置状态,它不需要有完整的控制器对象,正如您看到的控制器只是一个字符串。这是真的,但在运行时,为了让Angular计算解析,它需要创建控制器。在评估解析之前,它无法创建控制器。当每个文件都使用IIFE时,如何使控制器处于相同的闭包中?在构建时在连接的js周围添加IIFE。Uglify可以选择将代码包装成一个闭包,一个生命。这样,您的代码将在相同的生命周期内。这将在生产模式下工作,但在开发模式下不工作,因为开发模式不会运行任何丑陋的程序。我用一个解决方案更新了我的原始答案,该解决方案应能在有或没有构建过程的情况下工作。我喜欢它,除了您从
$window
而不是
$controller
获取控制器之外。是否可以使用
$controller
?不管怎样,我都会给你赏金,因为你尽了最大的努力来解决这个问题。不幸的是,这几乎是不可能的$控制器实例化控制器并尝试解析依赖项。但因为我们有自定义依赖项(解析参数)$controller会说它不知道“customers”参数。可以修饰$controllerProvider服务并覆盖其注册功能。这将提供一种获取控制器功能列表的方法。但如今,这是不允许的。Angular公开$get函数的结果,而不是实际的服务。所以“register”功能被忽略了,下一个选项是修改$injector。但是,angular不允许修饰这个服务,简单地重写它的方法也不会带来任何效果。好的,看起来你可以用provider函数重写$controllerProvider。通过这种方式,您可以向其添加必要的“getConstructor”,并避免使用$window对象获取控制器构造函数。我用这些新发现更新了plunker。我不建议实施此解决方案。UI Router 1.0不再使用
$resolve
服务,因此此解决方案的使用寿命有限。如前所述,此时控制器还不可用。我使用的设计模式是使用
解析器
服务。在解析函数作用域中使用
this.self.name
(您在其中发出
Customer.get()
请求),可以获取状态的名称。然后,执行类似于
返回解析器.prepare(this.self.name)
的操作,您可以将所有逻辑提取到
解析器中,并减少