AngularJS UI路由器-改变没有重载状态的url

时间:2022-08-26 21:00:13

Currently our project is using default $routeProvider, and I am using this "hack", to change url without reloading page:

目前我们的项目正在使用默认的$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;
}]);

and in controller

和控制器

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

I am thinking of replacing routeProvider with ui-router for nesting routes, but cant find this in ui-router.

我正在考虑用ui-router替代routeProvider来嵌套路由,但是在ui-router中找不到这个。

Is it possible - do the same with angular-ui-router?

有没有可能——对盎格鲁-ui-路由器做同样的事情?

Why do I need this? Let me explain with an example :
Route for creating new category is /category/new after clicking on SAVE I show success-alert and I want to change route /category/new to /caterogy/23 (23 - is id of new item stored in db)

为什么我需要这个?让我用一个例子来解释:创建新类别的路径是/category/new,在点击SAVE之后,我显示success-alert,我想要更改路径/category/new to /caterogy/23(23 -是存储在db中的新项目的id)

7 个解决方案

#1


138  

Simply you can use $state.transitionTo instead of $state.go . $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true } . You can call $state.transitionTo and set notify: false . For example:

只需使用$state即可。transitionTo代替美元的状态。走了。美元的状态。美元去调用状态。transitionTo在内部自动设置选项为{location: true, inheritance: true, relative: $state。$current, notify: true}。你可以叫美元状态。transitionTo和set notify: false。例如:

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

can be replaced by

可以更换的

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

Edit: As suggested by fracz it can simply be:

编辑:根据fracz的建议,它可以是:

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

#2


47  

Ok, solved :) Angular UI Router has this new method, $urlRouterProvider.deferIntercept() https://github.com/angular-ui/ui-router/issues/64

好,解决了:)角UI路由器有这个新方法,$urlRouterProvider.deferIntercept() https://github.com/angular-ui/ui- router/es/64。

basically it comes down to this:

基本上可以归结为:

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();
  }]);

I think this method is currently only included in the master version of angular ui router, the one with optional parameters (which are nice too, btw). It needs to be cloned and built from source with

我认为这个方法目前只包含在有角ui路由器的主版本中,这个版本有可选的参数(顺便说一句,这也不错)。它需要从源代码进行克隆和构建

grunt build

The docs are accessible from the source as well, through

文档也可以从源代码中访问

grunt ngdocs

(they get built into the /site directory) // more info in README.MD

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

There seems to be another way to do this, by dynamic parameters (which I haven't used). Many credits to nateabele.

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


As a sidenote, here are optional parameters in Angular UI Router's $stateProvider, which I used in combination with the above:

作为旁注,这里是角UI路由器的$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'
    });

}]);

what that does is it allows to resolve a state, even if one of the params is missing. SEO is one purpose, readability another.

它所做的是,它允许解析一个状态,即使其中一个params丢失了。SEO是一个目的,可读性是另一个目的。

In the example above, I wanted doorsSingle to be a required parameter. It is not clear how to define those. It works ok with multiple optional parameters though, so not really a problem. The discussion is here https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

在上面的示例中,我希望doorsSingle是必需的参数。目前还不清楚如何定义它们。它可以使用多个可选参数,所以不是问题。这里讨论的是https://github.com/angular- ui/uitrouter/pull/1032 #发行,49196090。

#3


12  

After spending a lot of time with this issue, Here is what I got working

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

$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
});

#4


7  

This setup solved following issues for me:

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

  • The training controller is not called twice when updating the url from .../ to .../123
  • 当从…更新url时,不会调用训练控制器两次。123年/…/
  • The training controller is not getting invoked again when navigating to another state
  • 当导航到另一个状态时,不会再次调用训练控制器

State configuration

国家配置

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
    }
})

Invoking the states (from any other controller)

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

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

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

Training Controller

训练控制器

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 ...
}   

#5


1  

i did this but long ago in version: v0.2.10 of UI-router like something like this::

我在很久以前的版本:UI-router像这样::

$stateProvider
  .state(
    'home', {
      url: '/home',
      views: {
        '': {
          templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
          controller: 'mainCtrl'
        },
      }
    })
  .state('home.login', {
    url: '/login',
    templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
    controller: 'authenticationCtrl'
  })
  .state('home.logout', {
    url: '/logout/:state',
    controller: 'authenticationCtrl'
  })
  .state('home.reservationChart', {
    url: '/reservations/?vw',
    views: {
      '': {
        templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
        controller: 'reservationChartCtrl',
        reloadOnSearch: false
      },
      'viewVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
        controller: 'viewVoucherCtrl',
        reloadOnSearch: false
      },
      'addEditVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
        controller: 'voucherCtrl',
        reloadOnSearch: false
      }
    },
    reloadOnSearch: false
  })

#6


1  

If you need only change url but prevent change state:

如果您只需要更改url,但阻止更改状态:

Change location with (add .replace if you want to replace in history):

将位置更改为(如果要在历史中进行替换,请添加.replace):

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

Prevent redirect to your state:

防止重定向到您的状态:

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

#7


-6  

I don't think you need ui-router at all for this. The documentation available for the $location service says in the first paragraph, "...changes to $location are reflected into the browser address bar." It continues on later to say, "What does it not do? It does not cause a full page reload when the browser URL is changed."

我觉得你根本不需要ui-router。$location服务的文档在第一段中写道,“……”$location的更改反映在浏览器地址栏中。它接着说,“它不做什么?”当浏览器URL被更改时,不会导致整个页面重新加载。

So, with that in mind, why not simply change the $location.path (as the method is both a getter and setter) with something like the following:

所以,考虑到这一点,为什么不简单地改变$location呢?路径(方法既是getter也是setter)如下:

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

The documentation notes that the path should always begin with a forward slash, but this will add it if it's missing.

文档指出,路径应该总是以斜杠开头,但如果缺少斜杠,则将添加斜杠。

#1


138  

Simply you can use $state.transitionTo instead of $state.go . $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true } . You can call $state.transitionTo and set notify: false . For example:

只需使用$state即可。transitionTo代替美元的状态。走了。美元的状态。美元去调用状态。transitionTo在内部自动设置选项为{location: true, inheritance: true, relative: $state。$current, notify: true}。你可以叫美元状态。transitionTo和set notify: false。例如:

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

can be replaced by

可以更换的

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

Edit: As suggested by fracz it can simply be:

编辑:根据fracz的建议,它可以是:

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

#2


47  

Ok, solved :) Angular UI Router has this new method, $urlRouterProvider.deferIntercept() https://github.com/angular-ui/ui-router/issues/64

好,解决了:)角UI路由器有这个新方法,$urlRouterProvider.deferIntercept() https://github.com/angular-ui/ui- router/es/64。

basically it comes down to this:

基本上可以归结为:

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();
  }]);

I think this method is currently only included in the master version of angular ui router, the one with optional parameters (which are nice too, btw). It needs to be cloned and built from source with

我认为这个方法目前只包含在有角ui路由器的主版本中,这个版本有可选的参数(顺便说一句,这也不错)。它需要从源代码进行克隆和构建

grunt build

The docs are accessible from the source as well, through

文档也可以从源代码中访问

grunt ngdocs

(they get built into the /site directory) // more info in README.MD

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

There seems to be another way to do this, by dynamic parameters (which I haven't used). Many credits to nateabele.

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


As a sidenote, here are optional parameters in Angular UI Router's $stateProvider, which I used in combination with the above:

作为旁注,这里是角UI路由器的$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'
    });

}]);

what that does is it allows to resolve a state, even if one of the params is missing. SEO is one purpose, readability another.

它所做的是,它允许解析一个状态,即使其中一个params丢失了。SEO是一个目的,可读性是另一个目的。

In the example above, I wanted doorsSingle to be a required parameter. It is not clear how to define those. It works ok with multiple optional parameters though, so not really a problem. The discussion is here https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

在上面的示例中,我希望doorsSingle是必需的参数。目前还不清楚如何定义它们。它可以使用多个可选参数,所以不是问题。这里讨论的是https://github.com/angular- ui/uitrouter/pull/1032 #发行,49196090。

#3


12  

After spending a lot of time with this issue, Here is what I got working

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

$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
});

#4


7  

This setup solved following issues for me:

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

  • The training controller is not called twice when updating the url from .../ to .../123
  • 当从…更新url时,不会调用训练控制器两次。123年/…/
  • The training controller is not getting invoked again when navigating to another state
  • 当导航到另一个状态时,不会再次调用训练控制器

State configuration

国家配置

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
    }
})

Invoking the states (from any other controller)

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

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

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

Training Controller

训练控制器

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 ...
}   

#5


1  

i did this but long ago in version: v0.2.10 of UI-router like something like this::

我在很久以前的版本:UI-router像这样::

$stateProvider
  .state(
    'home', {
      url: '/home',
      views: {
        '': {
          templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
          controller: 'mainCtrl'
        },
      }
    })
  .state('home.login', {
    url: '/login',
    templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
    controller: 'authenticationCtrl'
  })
  .state('home.logout', {
    url: '/logout/:state',
    controller: 'authenticationCtrl'
  })
  .state('home.reservationChart', {
    url: '/reservations/?vw',
    views: {
      '': {
        templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
        controller: 'reservationChartCtrl',
        reloadOnSearch: false
      },
      'viewVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
        controller: 'viewVoucherCtrl',
        reloadOnSearch: false
      },
      'addEditVoucher@home.reservationChart': {
        templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
        controller: 'voucherCtrl',
        reloadOnSearch: false
      }
    },
    reloadOnSearch: false
  })

#6


1  

If you need only change url but prevent change state:

如果您只需要更改url,但阻止更改状态:

Change location with (add .replace if you want to replace in history):

将位置更改为(如果要在历史中进行替换,请添加.replace):

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

Prevent redirect to your state:

防止重定向到您的状态:

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

#7


-6  

I don't think you need ui-router at all for this. The documentation available for the $location service says in the first paragraph, "...changes to $location are reflected into the browser address bar." It continues on later to say, "What does it not do? It does not cause a full page reload when the browser URL is changed."

我觉得你根本不需要ui-router。$location服务的文档在第一段中写道,“……”$location的更改反映在浏览器地址栏中。它接着说,“它不做什么?”当浏览器URL被更改时,不会导致整个页面重新加载。

So, with that in mind, why not simply change the $location.path (as the method is both a getter and setter) with something like the following:

所以,考虑到这一点,为什么不简单地改变$location呢?路径(方法既是getter也是setter)如下:

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

The documentation notes that the path should always begin with a forward slash, but this will add it if it's missing.

文档指出,路径应该总是以斜杠开头,但如果缺少斜杠,则将添加斜杠。