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

vul*_*iad 128 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;
}]);
Run Code Online (Sandbox Code Playgroud)

并在 controller

$locationEx.skipReload().path("/category/" + $scope.model.id).replace();
Run Code Online (Sandbox Code Playgroud)

我想到的替换routeProviderui-router筑巢路线,但无法找到这ui-router.

是否有可能 - 做同样的事情angular-ui-router

我为什么需要这个?让我用一个例子说明:
用于创建新类是路线/category/newclicking在SAVE我秀success-alert,我想改变路线/category/new,以/caterogy/23(23 -是存储在数据库新项目的ID)

rez*_*esh 158

只需使用 $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}) 
Run Code Online (Sandbox Code Playgroud)

可以替换为

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

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

$state.go('.detail', {id: newId}, {notify: false}) 
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,它使用以下内容:`$ state.transitionTo('.detail',{id:newId},{location:true,inherit:true,relative:$ state.$ current,notify:false})`所以基本上将notify设置为false,将location设置为true (25认同)
  • 是不是"在重新加载状态时保留URL"而不是"在没有重新加载状态的情况下更改URL"? (16认同)
  • 更简单:`$ state.go('.detail',{id:newId},{notify:false})`. (14认同)
  • @ArjendeVries是的它按预期工作但我发现了一个意想不到的行为.在你最终移动到一个新状态(即.url)后,玩了很多transitionTo方法调用(没有重新加载),它重新启动旧控制器. (6认同)
  • 网址永远不会在 Chrome 中更新。最近几个月这里有变化吗? (2认同)
  • @Premchandra Singh:这里有同样的问题.离开状态时,旧控制器再次初始化.我从wiherek接受的解决方案中遇到了同样的问题.另见https://github.com/angular-ui/ui-router/issues/64 (2认同)
  • 我知道这是旧的,但万一有人记得......我看到的问题与@PremchandraSingh和其他人一样.你有没有找到解决方案?我已经尝试设置{notify:false,reload:false,location:"replace",inherit:false}但是当它转移到新状态时它仍然会重新初始化控制器. (2认同)
  • 仅供参考,我已将ui.router升级到v1.0.0(来自"稳定版",我认为是v0.2.x)并且我不再看到旧控制器的重新初始化.它看起来像是固定的. (2认同)

wih*_*rek 48

好的,已经解决了 :) Angular UI路由器有这个新方法,$ 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();
  }]);
Run Code Online (Sandbox Code Playgroud)

我认为这种方法目前只包含在角度ui路由器的版本中,带有可选参数的那个(也很好,顺便说一句).它需要从源代码克隆和构建

grunt build
Run Code Online (Sandbox Code Playgroud)

文档也可以从源代码访问

grunt ngdocs
Run Code Online (Sandbox Code Playgroud)

(它们内置在/ 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'
    });

}]);
Run Code Online (Sandbox Code Playgroud)

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

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


Pan*_*kar 15

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

$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
});
Run Code Online (Sandbox Code Playgroud)

  • 我尝试了一下,每次我使用$ state.go时,组件上都会调用$ onInit()。对我来说似乎不是100%可以。 (2认同)

Mor*_*ler 9

Calling

$state.go($state.current, {myParam: newValue}, {notify: false});
Run Code Online (Sandbox Code Playgroud)

will still reload the controller, meaning you will lose state data.

To avoid it, simply declare the parameter as dynamic:

$stateProvider.state({
    name: 'myState',
    url: '/my_state?myParam',
    params: {
        myParam: {
          dynamic: true,    // <----------
        }
    },
    ...
});
Run Code Online (Sandbox Code Playgroud)

Then you don't even need the notify, just calling

$state.go($state.current, {myParam: newValue})
Run Code Online (Sandbox Code Playgroud)

suffices. Neato!

From the documentation:

When dynamic is true, changes to the parameter value will not cause the state to be entered/exited. The resolves will not be re-fetched, nor will views be reloaded.

This can be useful to build UI where the component updates itself when the param values change.


mar*_*oss 7

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

  • 从更新的URL时,训练控制器不叫两声.../,以.../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
    }
})
Run Code Online (Sandbox Code Playgroud)

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

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

$scope.newTraining = function () {
    $state.go('training.new', { });
};
Run Code Online (Sandbox Code Playgroud)

培训控制员

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 ...
}   
Run Code Online (Sandbox Code Playgroud)