Ui-router加载状态,然后我怎么运行一个函数

Ui-router loads state, then how can I run a function?

本文关键字:函数 一个 运行 状态 加载 然后 Ui-router      更新时间:2023-09-26

我是Angular和state的新手,对ui-router也很感兴趣。我用jQuery做这件事已经太久了。在jQuery中,我可以用ajax加载一些东西,然后在成功后运行另一个函数。如何在Angular中做到这一点呢?

例如,我有以下

var ivApp = angular.module('ivApp', ['ui.router']);
ivApp.config(function($urlRouterProvider, $stateProvider){
  $urlRouterProvider.otherwise('/');
  $stateProvider
    .state('home', {
      url: '/',
      templateUrl: 'partials/partial-home.html'
    })
 });

partial-home.html加载到ui-view中。但是,一旦完成,如何告诉它运行一个函数?例如,我有authenticate.js和函数authenticate()。我如何运行authenticate()一旦'home'状态已加载?

另外,我能告诉angular只在这个状态下加载authenticate.js吗?或者我应该已经把它加载到模板中了。我知道,如果我在partial-home.html中包含脚本(例如<script src="authenticate.js"></script>), chrome会抛出关于同步xmlhttprest被弃用的错误。我能不能在配置中声明authenticate。js为状态依赖之类的?

目前我已经算出来了,我可以这样做:

ivApp.controller('authenticate', function($scope) {
  // start authorisation
  authenticate();
});

然后在我的ui-router状态中定义控制器认证。但事情就是这样的吗?它基本上是有效的。我的身份验证函数正在做一些事情,比如改变DOM中的东西,但我读到控制器不应该用于此。

谢谢你的指点

我们来分析一下。

如果你只想在这个特定的home状态下加载authenticate.js,使用ocLazyLoad。这是惰性加载资源的最佳方式之一。它的工作真的很好,如果ui-路由器也是!

    $stateProvider.state('index', {
      url: "/", // root route
      views: {
        "lazyLoadView": {
          controller: 'AppCtrl', // This view will use AppCtrl loaded below in the resolve
          templateUrl: 'partial-home.html'
        }
      },
      resolve: { // Any property in resolve should return a promise and is executed before the view is loaded
        loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
          // you can lazy load files for an existing module
                 return $ocLazyLoad.load('js/authenticate.js');
        }]
      }
    });

如果您想在加载状态后运行authenticate(),有很多方法可以做到这一点。当然,一种方法是收听$stateChangeSuccess事件,但我会避免使用它,因为你知道,全局变量,全局变量是不好的。我不想仅仅因为我有一个真正特定的用例而污染我的$rootScope

你也可以在ui-router中使用resolveResolve在控制器实例化前加载状态后执行。我建议使用这种方法,因为如果你正在使用它(你应该使用它),你可以将你的承诺与ocLazyLoad链接在一起。

加载状态后操纵dom ?当然,这就是templateUrl的作用!设计你的模板,使它适应你的authenticate()函数。如果你把它和resolve结合起来,分离关注点并没有太大的问题,因为你已经在控制器加载之前执行了authenticate()

编辑:添加Plnkr

您想首先惰性加载authenticate.js,然后使用 authenticate.js内部的函数来做一些事情。由于ui.router中的resolve并行执行承诺链,我们必须将它们链接起来,即首先加载您的jsfiles,然后返回您的身份验证状态。

我们需要使用$q服务声明一个延迟承诺。然后我们在resolve中返回这个promise,这样你的控制器就会监听一个promise而不是两个promise。方法如下:

 $stateProvider
  .state('Home', {
    templateUrl: 'home.html',
    controller: 'homeCtrl',
    resolve: {
      //need to chain our promises since we neeed to first load the authenticate.js
      //and second, execute authenticate()
      loadJsAndAuth: ['$ocLazyLoad', '$q', '$injector', function($ocLazyLoad, $q, $injector) {
        //declare a deferred promise
        var deferred = $q.defer();
        //now load the authenticate.js
        $ocLazyLoad.load('authenticate.js').then(
          //load successful! proceed to use our authenticate function!
          function(success) {
            //since we already have loaded authenticatejs, now we can inject the service and use it
            var authSvc = $injector.get('authenticateSvc');
            //this is just a demo on how to authenticate. 
            //change this to banana to see the authenticate fail
            var fruits = 'apple'
            if (authSvc.authenticate(fruits)) {
              //authenticate pass, resolve the promise!
              deferred.resolve('authenticated!');
            }
            //authenticate fail, reject the promise
            deferred.reject('authenticate failed');
          },
          //load of jsfiles failed! reject the promise.
          function(error) {
            deferred.reject('Cannot load authenticate.js')
          })
        return deferred.promise;
      }]
    }
  })

在你的控制器中,你可以得到解决的承诺!

//you can get access to what is is being resolved by loadJsAndAuth
.controller('homeCtrl', ['$scope', 'loadJsAndAuth', function($scope, loadJsAndAuth) {
  $scope.status = loadJsAndAuth // this is resolved promises.
}]);