AngularJS UI路由器 - 在不重新加载状态的情况下更改URL

时间:2014-05-10 18:56:37

标签: angularjs angular-ui-router

目前我们的项目使用默认$routeProvider,我正在使用此" hack",更改url而不重新加载页面:

services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
    $location.skipReload = function () {
        var lastRoute = $route.current;
        var un = $rootScope.$on('$locationChangeSuccess', function () {
            $route.current = lastRoute;
            un();
        });
        return $location;
    };
    return $location;
}]);

并在controller

$locationEx.skipReload().path("/category/" + $scope.model.id).replace();

我正在考虑将routeProvider替换为ui-router用于嵌套路由,但无法在ui-router中找到它。

是否可以 - 对angular-ui-router执行相同的操作?

为什么我需要这个? 让我用一个例子来解释:
创建新类别的路线是/category/new 在SAVE clicking之后我显示success-alert并且我想将路由/category/new更改为/caterogy/23(23 - 是存储在db中的新项目的ID)

9 个答案:

答案 0 :(得分:152)

您只需使用 $state.transitionTo 代替 $state.go 即可。 $state.go 在内部调用 $state.transitionTo ,但会自动将选项设置为 { location: true, inherit: true, relative: $state.$current, notify: true } 。您可以致电 $state.transitionTo 并设置 notify: false 。例如:

$state.go('.detail', {id: newId}) 

可以替换为

$state.transitionTo('.detail', {id: newId}, {
    location: true,
    inherit: true,
    relative: $state.$current,
    notify: false
})

编辑:正如fracz所建议的,它可以简单地说:

$state.go('.detail', {id: newId}, {notify: false}) 

答案 1 :(得分:48)

好的,解决了 :) Angular UI Router有这个新方法,$ urlRouterProvider.deferIntercept() https://github.com/angular-ui/ui-router/issues/64

基本上归结为:

angular.module('myApp', [ui.router])
  .config(['$urlRouterProvider', function ($urlRouterProvider) {
    $urlRouterProvider.deferIntercept();
  }])
  // then define the interception
  .run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
    $rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
      // Prevent $urlRouter's default handler from firing
      e.preventDefault();

      /** 
       * provide conditions on when to 
       * sync change in $location.path() with state reload.
       * I use $location and $state as examples, but
       * You can do any logic
       * before syncing OR stop syncing all together.
       */

      if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
        // your stuff
        $urlRouter.sync();
      } else {
        // don't sync
      }
    });
    // Configures $urlRouter's listener *after* your custom listener
    $urlRouter.listen();
  }]);

我认为这种方法目前只包含在angular ui路由器的 master 版本中,带有可选参数的那个(也很好,顺便说一句)。它需要克隆并使用

从源代码构建
grunt build

也可以通过

从源代码访问文档
grunt ngdocs

(它们内置于/ site目录中)// README.MD中的更多信息

似乎还有另一种方法,通过动态参数(我还没有使用过)。 nateabele有很多学分。


作为旁注,这里是Angular UI Router的$ stateProvider中的可选参数,我将其与上述结合使用:

angular.module('myApp').config(['$stateProvider', function ($stateProvider) {    

  $stateProvider
    .state('main.doorsList', {
      url: 'doors',
      controller: DoorsListCtrl,
      resolve: DoorsListCtrl.resolve,
      templateUrl: '/modules/doors/doors-list.html'
    })
    .state('main.doorsSingle', {
      url: 'doors/:doorsSingle/:doorsDetail',
      params: {
        // as of today, it was unclear how to define a required parameter (more below)
        doorsSingle: {value: null},
        doorsDetail: {value: null}
      },
      controller: DoorsSingleCtrl,
      resolve: DoorsSingleCtrl.resolve,
      templateUrl: '/modules/doors/doors-single.html'
    });

}]);

它的作用是它允许解决一个状态,即使其中一个参数缺失。 SEO是一个目的,可读性另一个。

在上面的示例中,我希望doorsSingle成为必需参数。目前尚不清楚如何定义这些。它可以使用多个可选参数,但不是真正的问题。讨论在https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

答案 2 :(得分:13)

在这个问题上花了很多时间后,这就是我的工作

$state.go('stateName',params,{
    // prevent the events onStart and onSuccess from firing
    notify:false,
    // prevent reload of the current state
    reload:false, 
    // replace the last record when changing the params so you don't hit the back button and get old params
    location:'replace', 
    // inherit the current params on the url
    inherit:true
});

答案 3 :(得分:7)

此设置为我解决了以下问题:

  • 将网址从.../更新为.../123
  • 时,系统不会调用两次训练控制器
  • 导航到其他州时,不会再次调用训练控制器

州配置

state('training', {
    abstract: true,
    url: '/training',
    templateUrl: 'partials/training.html',
    controller: 'TrainingController'
}).
state('training.edit', {
    url: '/:trainingId'
}).
state('training.new', {
    url: '/{trainingId}',
    // Optional Parameter
    params: {
        trainingId: null
    }
})

调用状态(来自任何其他控制器)

$scope.editTraining = function (training) {
    $state.go('training.edit', { trainingId: training.id });
};

$scope.newTraining = function () {
    $state.go('training.new', { });
};

培训控制器

var newTraining;

if (!!!$state.params.trainingId) {

    // new      

    newTraining = // create new training ...

    // Update the URL without reloading the controller
    $state.go('training.edit',
        {
            trainingId : newTraining.id
        },
        {
            location: 'replace', //  update url and replace
            inherit: false,
            notify: false
        });     

} else {

    // edit

    // load existing training ...
}   

答案 4 :(得分:3)

如果您只需要更改网址但阻止更改状态:

更改位置(如果要在历史记录中替换,请添加.replace):

this.$location.path([Your path]).replace();

防止重定向到您的州:

$transitions.onBefore({}, function($transition$) {
 if ($transition$.$to().name === '[state name]') {
   return false;
 }
});

答案 5 :(得分:2)

我做了这个,但很久以前版本:UI-router的v0.2.10就像这样::

collection('myDocs')[root/@myAtt = 'one']

答案 6 :(得分:1)

致电

$state.go($state.current, {myParam: newValue}, {notify: false});

仍会重新加载控制器。

为避免这种情况,必须将参数声明为dynamic:

$stateProvider.state({
    name: 'myState',
    url: '/my_state?myParam',
    params: {
        myParam: {
          dynamic: true,
        }
    },
    ...
});

然后,您甚至都不需要notify,只需致电

$state.go($state.current, {myParam: newValue})

足够了。尼阿托!

来自documentation

  

dynamictrue时,对参数值的更改将   不会导致状态进入/退出。解决办法不会   重新获取,也不会重新加载视图。

     

[...]

     

这对构建很有用   当参数值更改时组件将自行更新的用户界面。

答案 7 :(得分:0)

尝试这样的事情

$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})

答案 8 :(得分:-6)

我认为你根本不需要ui-router。可用于$location service的文档在第一段中说,“...对$ location的更改会反映到浏览器地址栏中。”它继续说,“它不做什么?当浏览器URL被更改时,它不会导致整页重新加载。”

因此,考虑到这一点,为什么不简单地更改$ location.path(因为该方法既是getter又是setter),具体如下:

var newPath = IdFromService;
$location.path(newPath);

documentation注意到路径应始终以正斜杠开头,但如果缺少正斜杠则会添加它。