AngularJS ui Router-изменение url без перезагрузки состояния

в настоящее время наш проект использует default $routeProvider, и я использую этот "хак", чтобы изменить 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 после clicking на SAVE я показываю success-alert и я хочу изменить маршрут /category/new to /caterogy/23 (23 - это идентификатор нового элемента, хранящегося в БД)

8 ответов


просто вы можете использовать $state.transitionTo вместо $state.go . $state.go звонки $state.transitionTo внутренне, но автоматически устанавливает параметры в { location: true, inherit: true, relative: $state.$current, notify: true } . Вы можете позвонить $state.transitionTo и set notify: false . Например:

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

можно заменить на

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

Edit: как предложил fracz, это может быть просто:

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

ОК, решена :) Угловой маршрутизатор 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();
  }]);

Я думаю, что этот метод в настоящее время включены только в мастер версия углового ui-маршрутизатора, с дополнительными параметрами (которые тоже хороши, кстати). Он должен быть клонирован и построен из источника с

grunt build

документы также доступны из источника, через

grunt ngdocs

(они встроены в каталоге /сайте) // подробнее в README.МД

кажется, есть другой способ сделать это, с помощью динамических параметров (который я не использовал). Много кредитов nateabele.


в качестве sidenote, вот дополнительные параметры в угловом 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'
    });

}]);

это позволяет разрешить состояние, даже если один из параметров отсутствует. SEO-одна цель, читаемость-другая.

в приведенном выше примере я хотел, чтобы doorsSingle был обязательным параметром. Не ясно, как их определить. Он работает нормально с несколькими дополнительными параметрами, поэтому на самом деле это не проблема. Обсуждение здесь https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090


проведя много времени с этой проблемой, вот что я получил работу

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

Эта настройка решила следующие проблемы для меня:

  • контроллер обучения не вызывается дважды при обновлении url из .../ to .../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 ...
}   

Если вам нужно только изменить url, но предотвратить изменение состояния:

изменить местоположение с помощью (add .заменить, если вы хотите заменить в истории):

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

предотвратить перенаправление в ваше состояние:

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

Я сделал это, но давно в версии: v0.2.10 из 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
  })

попробуйте что-то вроде этого

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

Я не думаю, что вам нужен ui-router вообще для этого. Документация, доступная для $location service написано в первом абзаце "...изменения в $location отражаются в адресной строке браузера. Позже он продолжает говорить: "чего он не делает? Это не вызывает полной перезагрузки страницы при изменении URL-адреса браузера."

Итак, имея это в виду, почему бы просто не изменить местоположение$.путь (как метод геттер и сеттер) с чем-то подобным следующее:

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

на документация отмечает, что путь всегда должен начинаться с косой черты, но это будет добавить его, если он отсутствует.