Можете ли вы изменить путь без перезагрузки контроллера в AngularJS?

Это'спросили раньше, и из ответов это нене выглядит хорошо. Я'Я хотел бы спросить с этим примером кода в рассмотрении ...

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

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

проблемаЯ хотел бы использовать разные пути для каждого контроллера без перезагрузки Item.html.

1) это возможно?

2) Если это невозможно, есть ли лучший подход к созданию пути на контроллер по сравнению с тем, что я придумал здесь?

app.js

var app = angular.module('myModule', []).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/items', {templateUrl: 'partials/items.html',   controller: ItemsCtrl}).
      when('/items/:itemId/foo', {templateUrl: 'partials/item.html', controller: ItemFooCtrl}).
      when('/items/:itemId/bar', {templateUrl: 'partials/item.html', controller: ItemBarCtrl}).
      otherwise({redirectTo: '/items'});
    }]);

Item.html


<a id="fooTab" my-active-directive="view.name" href="#/item/{{item.id}}/foo">Foo</a>
<a id="barTab" my-active-directive="view.name" href="#/item/{{item.id}}/bar">Bar</a>


controller.js

// Helper function to load $scope.item if refresh or directly linked
function itemCtrlInit($scope, $routeParams, MyService) {
  $scope.item = MyService.currentItem;
  if (!$scope.item) {
    MyService.currentItem = MyService.get({itemId: $routeParams.itemId});
    $scope.item = MyService.currentItem;
  }
}
function itemFooCtrl($scope, $routeParams, MyService) {
  $scope.view = {name: 'foo', template: 'partials/itemFoo.html'};
  itemCtrlInit($scope, $routeParams, MyService);
}
function itemBarCtrl($scope, $routeParams, MyService) {
  $scope.view = {name: 'bar', template: 'partials/itemBar.html'};
  itemCtrlInit($scope, $routeParams, MyService);
}

Разрешение.

Статус: Использование поискового запроса, как рекомендовано в принятом ответе, позволило мне предоставить разные URL-адреса без перезагрузки основного контроллера.

app.js

var app = angular.module('myModule', []).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/items', {templateUrl: 'partials/items.html',   controller: ItemsCtrl}).
      when('/item/:itemId/', {templateUrl: 'partials/item.html', controller: ItemCtrl, reloadOnSearch: false}).
      otherwise({redirectTo: '/items'});
    }]);

Item.html


<a href="#/item/{{item.id}}/?view=foo">Foo</a>
<a href="#/item/{{item.id}}/?view=foo">Bar</a>



controller.js

function ItemCtrl($scope, $routeParams, Appts) {
  $scope.views = {
    foo: {name: 'foo', template: 'partials/itemFoo.html'},
    bar: {name: 'bar', template: 'partials/itemBar.html'},
  }
  $scope.view = $scope.views[$routeParams.view];
}

directives.js

app.directive('itemTab', function(){
  return function(scope, elem, attrs) {
    scope.$watch(attrs.itemTab, function(val) {
      if (val+'Tab' == attrs.id) {
        elem.addClass('active');
      } else {
        elem.removeClass('active');
      }
    });
  }
});

Содержимое внутри моих частей обернутоng-controller=...

 robert king24 мар. 2015 г., 08:41
нашел этот ответ:stackoverflow.com/a/18551525/632088 - он использует reloadOnSearch: false, но также проверяет наличие обновлений URL-адреса в строке поиска (например, если пользователь нажимает кнопку «Назад» и изменения URL)

Ответы на вопрос(11)

Есть простой способ изменить путь без перезагрузки

URL is - http://localhost:9000/#/edit_draft_inbox/1457

Используйте этот код для изменения URL, страница не будет перенаправлена

Второй параметрложный" очень важно.

$location.path('/edit_draft_inbox/'+id, false);
Решение Вопроса

почему бы просто не поставить ng-контроллер на один уровень выше,


    

И не надоустановить контроллер на маршруте,

.when('/', { templateUrl: "abc.html" })

меня устраивает.

 Raptor25 апр. 2016 г., 17:12
Спасибо! Просто работает!
 daveoncode17 мар. 2015 г., 12:23
отличный совет, он отлично работает и для моего сценария! Большое спасибо! :)
 inolasco19 мар. 2015 г., 22:53
Это здороворусские использовали карандаши ответь, у меня работает :)
 inolasco21 мая 2015 г., 00:11
@ plong0 Хороший вопрос, должно работать. Однако в моем случае мне нужно было получить значения URL только при загрузке контроллера при загрузке страницы, чтобы инициализировать определенные значения. В итоге я использовал решение, предложенное vigrond, с использованием $ locationChangeSuccess, но у вас также есть еще один допустимый вариант.
 plong019 мая 2015 г., 23:14
@inolasco: работает, если вы читаете свои $ routeParams в обработчике $ routeChangeSuccess. Чаще всего это, вероятно, то, что вы хотите в любом случае. чтение только в контроллере даст вам только те значения для URL, который был изначально загружен.
 inolasco20 мар. 2015 г., 00:49
Я говорил слишком рано. Этот обходной путь заключается в том, что если вам нужно загрузить значения из $ routeParams в контроллер, они не будут загружаться, по умолчанию {}

добавьте его после .config в файле приложения. Тогда вы можете сделать$location.path('/sampleurl', false); предотвратить перегрузку

app.run(['$route', '$rootScope', '$location', function ($route, $rootScope, $location) {
    var original = $location.path;
    $location.path = function (path, reload) {
        if (reload === false) {
            var lastRoute = $route.current;
            var un = $rootScope.$on('$locationChangeSuccess', function () {
                $route.current = lastRoute;
                un();
            });
        }
        return original.apply($location, [path]);
    };
}])

Кредит идет вhttps://www.consolelog.io/angularjs-change-path-without-reloading для самого элегантного решения янашел.

 Lajos Meszaros20 авг. 2015 г., 12:26
Это решение все еще делает перезагрузку представления.
 snowindy11 окт. 2015 г., 12:32
Я должен был добавить$timeout(un, 200); перед возвращением заявления как иногда$locationChangeSuccess вообще не стрелялapply (и маршрут не был изменен, когда действительно необходимо). Мое решение очищает вещи после вызова пути (..., ложь)
 Mark B30 июл. 2014 г., 23:52
Отличное решение. В любом случае, чтобы получить браузер?кнопка назад к "честь" этот?
 Thiago Pereira06 дек. 2018 г., 14:17
Отлично работает наAngularJS 1.5
 jornare08 авг. 2014 г., 15:37
Помните, что это решение сохраняет старый маршрут, и если вы запросите $ route.current, вы получите предыдущий путь, а не текущий. В противном случае это отличный маленький взломать.
 Will Hitchcock13 апр. 2015 г., 19:53
Некоторое время мы использовали это решение и просто заметили, что при некоторых изменениях пути перезагрузите регистры как ложные, даже когда передается истинное значение. У кого-нибудь еще были такие проблемы?
 Satish Singh13 апр. 2016 г., 10:52
Это то, что я искал. Спасибо, гики, вы спасли мой день.
 chipit2417 сент. 2014 г., 06:25
Просто хотел сказать, что оригинальное решение было на самом деле опубликованоEvanWinstanley» Вот:github.com/angular/angular.js/issues/1699#issuecomment-34841248I»
 Rober28 мая 2019 г., 10:16
Эй, я просто копирую и вставляю, но я получаю TypeError: $ rootScope. $ On не является функцией. Что мне не хватает? Какая минимальная версия AngularJS использует этот подход?
 Kunal Dethe02 июн. 2016 г., 19:57
Есть ли способ реализовать то же самое с помощью ui-router?
 Oded Niv27 сент. 2016 г., 12:05
Зацени мое решение, добавил кое-что, что не сделал твойт. Не стесняйтесь взять чтопропал и прокомментируй мой и яЯ удалю мой ответ.
 Hashan Kanchana26 апр. 2016 г., 05:55
попробовал это решение и обнаружил, что некоторые переменные $ scope не могут использоваться после изменения маршрута. Поэтому необходимо снова создать все объекты и переменные, поскольку он возвращает false, когда пытается использовать $ scope.variables после изменения подстраницы.

кому нужно изменить path () без перезагрузки контроллеров - вот плагин:https://github.com/anglibs/angular-location-update

Использование:

$location.update_path('/notes/1');

На основеhttps://stackoverflow.com/a/24102139/1751321

Постскриптум Это решениеhttps://stackoverflow.com/a/24102139/1751321 содержит ошибку после вызванного пути (, false) - она будет нарушать навигацию браузера вперед / назад до вызова пути (, true)

 lwdthe122 дек. 2017 г., 02:08
Это хорошо работает. Спасибо!

использование reloadOnSeach = false не решает проблему для тех из нас, кому необходимо изменить фактический путь, а не только параметры. Вот'Это простое решение для рассмотрения:

Используйте ng-include вместо ng-view и назначьте свой контроллер в шаблоне.

<!-- In your index.html - instead of using ng-view -->
<div ng-include="templateUrl"></div>

<!-- In your template specified by app.config -->
<div ng-controller="MyController">{{variableInMyController}}</div>

//in config
$routeProvider
  .when('/my/page/route/:id', { 
    templateUrl: 'myPage.html', 
  })

//in top level controller with $route injected
$scope.templateUrl = ''

$scope.$on('$routeChangeSuccess',function(){
  $scope.templateUrl = $route.current.templateUrl;
})

//in controller that doesn't reload
$scope.$on('$routeChangeSuccess',function(){
  //update your scope based on new $routeParams
})

Единственным недостатком является то, что вы не можете использовать атрибут разрешения, но этодовольно легко обойти. Также вы должны управлять состоянием контроллера, например, логикой, основанной на $ routeParams, когда маршрут изменяется внутри контроллера, когда изменяется соответствующий URL.

Вот'Вот пример:http://plnkr.co/edit/WtAOm59CFcjafMmxBVOP?p=preview

 Gil Birman25 сент. 2013 г., 10:26
Кнопка возврата нет работа (демо планкр в собственном окне)
 Lukus25 сент. 2013 г., 23:15
Не уверен, что кнопка возврата будет работать правильно в plnkr ... Как я уже говорил, вам придется управлять некоторыми вещами самостоятельно, когда меняется маршрут .. это 'не самое достойное кода решение, но оно работает
Решение Вопроса

#/item/{{item.id}}/foo а также#/item/{{item.id}}/bar но#/item/{{item.id}}/?foo а также#/item/{{item.id}}/?bar вместо этого вы можете настроить свой маршрут для/item/{{item.id}}/ иметьreloadOnSearch установлен в (falsedocs.angularjs.org/api/ngRoute.$routeProvider). Это говорит AngularJS не перезагружать представление, если изменяется поисковая часть URL.

 Coder120 февр. 2013 г., 09:42
Понял. Добавил параметр контроллера в мой массив просмотра, затем добавилng-controller="view.controller" кng-include директивы.
 Coder120 февр. 2013 г., 12:47
Проблемы с областью не были связаны. Это решено, и я обновил решение. Еще раз спасибо.
 Anders Ekdahl20 февр. 2013 г., 09:42
Вы должны создать часы для $ location.search () в itemCtrlInit и, в зависимости от параметра поиска, обновить $ scope.view.template. И тогда эти шаблоны могут быть обернуты чем-то вроде... your template content..., РЕДАКТИРОВАТЬ: Приятно видеть, что вы решили, было бы здорово, если бы вы обновили свой вопрос, как вы решили, возможно, с помощью jsFiddle.I '
 Coder120 февр. 2013 г., 11:29
Я не былне уверен, как jsFiddle несколько частичных. Я оставил свой прогресс выше, что касается первоначального вопроса о возможности использования URL-адресов без перезагрузки корневого контроллера. Я'Я собираюсь вернуться к вопросам охвата позже сегодня. Вы определенно сделали меня на правильном пути, спасибо!
 Chris Chevalier18 нояб. 2016 г., 18:53
Вот это да. Наконец-то понял, почему мое приложение было таким медленным. Я менял параметры поиска каждый раз, когда пользователь взаимодействовал. Didn»Я знаю, что это все перезагружается.
 Rhys van der Waerden11 февр. 2014 г., 02:35
Следует отметить, что вы нена самом деле нужно переформатировать ваши URL-адреса. Это может быть тот случай, когда ответ был опубликован, но документация (docs.angularjs.org/api/ngRoute.$routeProvider) теперь говорит:[reloadOnSearch = true] - {boolean =} - перезагрузить маршрут при изменении только $ location.search () или $ location.hash ().
 Coder120 февр. 2013 г., 08:44
Спасибо за это. Я'Я пытаюсь выяснить, где я бы сменил контроллер.
 Anders Ekdahl20 февр. 2013 г., 10:46
Если вы можете изолировать вашу проблему в jsFiddle / plnkr / etc, я 'Я уверен, что мы можем помочь вам с этим.
 Coder120 февр. 2013 г., 10:24
Я обновлю его, когда ям 100% там. Я'У меня есть некоторые причуды с областью действия в дочерних контроллерах и ng-click. Если я загружаю напрямую из foo, ng-click выполняется в области foo. Затем я нажимаю на панель, и ng-клики в этом шаблоне выполняются в родительской области.
 Illidan08 авг. 2015 г., 20:41
Для всех, кто интересуется, существует тот же параметр для маршрутизатора пользовательского интерфейса - вы можете установить состояние "reloadOnSearch: false "

s мое более полное решение, которое решает несколько вещей, которые пропустили @Vigrond и @rahilwazir:

Когда параметры поиска были изменены, это предотвратит трансляцию.$routeUpdateКогда маршрут фактически оставлен без изменений,$locationChangeSuccess никогда не срабатывает, что вызываетследующий обновление маршрута должно быть предотвращено.

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

app.run(['$rootScope', '$route', '$location', '$timeout', function ($rootScope, $route, $location, $timeout) {
    ['url', 'path'].forEach(function (method) {
        var original = $location[method];
        var requestId = 0;
        $location[method] = function (param, reload) {
            // getter
            if (!param) return original.call($location);

            # only last call allowed to do things in one digest cycle
            var currentRequestId = ++requestId;
            if (reload === false) {
                var lastRoute = $route.current;
                // intercept ONLY the next $locateChangeSuccess
                var un = $rootScope.$on('$locationChangeSuccess', function () {
                    un();
                    if (requestId !== currentRequestId) return;

                    if (!angular.equals($route.current.params, lastRoute.params)) {
                        // this should always be broadcast when params change
                        $rootScope.$broadcast('$routeUpdate');
                    }
                    var current = $route.current;
                    $route.current = lastRoute;
                    // make a route change to the previous route work
                    $timeout(function() {
                        if (requestId !== currentRequestId) return;
                        $route.current = current;
                    });
                });
                // if it didn't fire for some reason, don't intercept the next one
                $timeout(un);
            }
            return original.call($location, param);
        };
    });
}]);
 Oded Niv18 окт. 2016 г., 07:35
Исправлена. Хм странно, это работает для меня, хотя на URL-адрес HTML5. Может все еще помочь кому-то, я думаю ...
 deltree18 окт. 2016 г., 02:58
опечаткаpath в конце должно бытьparamТоже это нене работает с хешами, а URL в моей адресной строке нет обновление

  <script type="text/javascript">
    angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />'));
  </script>

Это предотвратит перезагрузку.

Я использую это решение

angular.module('reload-service.module', [])
.factory('reloadService', function($route,$timeout, $location) {
  return {
     preventReload: function($scope, navigateCallback) {
        var lastRoute = $route.current;

        $scope.$on('$locationChangeSuccess', function() {
           if (lastRoute.$route.templateUrl === $route.current.$route.templateUrl) {
              var routeParams = angular.copy($route.current.params);
              $route.current = lastRoute;
              navigateCallback(routeParams);
           }
        });
     }
  };
})

//usage
.controller('noReloadController', function($scope, $routeParams, reloadService) {
     $scope.routeParams = $routeParams;

     reloadService.preventReload($scope, function(newParams) {
        $scope.routeParams = newParams;
     });
});

Этот подход сохраняет функциональность кнопки возврата, и у вас всегда есть текущий routeParams в шаблоне, в отличие от некоторых других подходов, которые явидел.

в том числе GitHub, имели некоторые проблемы для моего сценария, а также кнопка «Назад» или прямое изменение URL из браузера перезагружало контроллер, что мне не нравилось. Я наконец пошел со следующим подходом:

1. Определите свойство в определениях маршрутов, называемое 'noReload» для тех маршрутов, где вы нене хочу, чтобы контроллер перезагружался при изменении маршрута.

.when('/:param1/:param2?/:param3?', {
    templateUrl: 'home.html',
    controller: 'HomeController',
    controllerAs: 'vm',
    noReload: true
})

2. В функции запуска вашего модуля поместите логику, которая проверяет эти маршруты. Это предотвратит перезагрузку, только еслиnoReload являетсяtrue и предыдущий контроллер маршрута такой же.

fooRun.$inject = ['$rootScope', '$route', '$routeParams'];

function fooRun($rootScope, $route, $routeParams) {
    $rootScope.$on('$routeChangeStart', function (event, nextRoute, lastRoute) {
        if (lastRoute && nextRoute.noReload 
         && lastRoute.controller === nextRoute.controller) {
            var un = $rootScope.$on('$locationChangeSuccess', function () {
                un();
                // Broadcast routeUpdate if params changed. Also update
                // $routeParams accordingly
                if (!angular.equals($route.current.params, lastRoute.params)) {
                    lastRoute.params = nextRoute.params;
                    angular.copy(lastRoute.params, $routeParams);
                    $rootScope.$broadcast('$routeUpdate', lastRoute);
                }
                // Prevent reload of controller by setting current
                // route to the previous one.
                $route.current = lastRoute;
            });
        }
    });
}

3. Наконец, в контроллере слушайте событие $ routeUpdate, чтобы вы могли делать все, что вам нужно, когда изменяются параметры маршрута.

HomeController.$inject = ['$scope', '$routeParams'];

function HomeController($scope, $routeParams) {
    //(...)

    $scope.$on("$routeUpdate", function handler(route) {
        // Do whatever you need to do with new $routeParams
        // You can also access the route from the parameter passed
        // to the event
    });

    //(...)
}

Имейте в виду, что при таком подходе вы неt изменить вещи в контроллере и затем обновить путь соответственно. Это'С другой стороны. Сначала вы изменяете путь, затем слушаете событие $ routeUpdate, чтобы изменить вещи в контроллере при изменении параметров маршрута.

Это делает вещи простыми и последовательными, поскольку вы можете использовать одну и ту же логику как при простом изменении пути (но без дорогостоящих запросов $ http, если хотите), так и при полной перезагрузке браузера.

Начиная с версии 1.2, вы можете использовать$ Location.replace ():

$location.path('/items');
$location.replace();

Ваш ответ на вопрос