Обновление URL-адреса в Angular JS без повторного рендеринга представления


79

Я создаю систему панелей управления в AngularJS, и у меня возникла проблема с настройкой URL-адреса через $location.path

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

В настоящее время у нас есть 2 маршрута, которые выглядят как /dashboard/:dashboardIdи/dashboard/:dashboardId/:maximizedWidgetId

Когда пользователь разворачивает виджет, мы обновляем URL-адрес, используя $location.path, но это вызывает повторную визуализацию представления. Поскольку у нас есть все данные, мы не хотим перезагружать все представление, мы просто хотим обновить URL-адрес. Есть ли способ установить URL-адрес без повторного рендеринга представления?

HTML5Modeустановлен на true.


1
Если вы хотите, чтобы ваши данные пережили изменения маршрута на стороне клиента, почему бы не отправить их в службу?
Riko

Ответы:


133

Фактически, представление будет отображаться каждый раз, когда вы меняете URL-адрес. Вот как $ routeProvider работает в Angular, но вы можете передать его maximizeWidgetIdкак строку запроса, которая не отображает представление повторно.

App.config(function($routeProvider) {
  $routeProvider.when('/dashboard/:dashboardId', {reloadOnSearch: false});
});

Когда вы щелкаете виджет, чтобы увеличить его:

<a href="#/dashboard/1?maximizeWidgetId=1">Maximum This Widget</a>
or
$location.search('maximizeWidgetId', 1);

URL-адрес в адресной строке изменится на http://app.com/dashboard/1?maximizeWidgetId=1

Вы даже можете наблюдать, когда поиск меняется в URL (с одного виджета на другой)

$scope.$on('$routeUpdate', function(scope, next, current) {
   // Minimize the current widget and maximize the new one
});

1
Если ответ будет принят, я создам отдельный вопрос без каких-либо вещей ": param". Просто глупый вопрос: как не перерисовывать вид.
OZ_

2
Я думаю, что в этом случае очевидным выбором будет angular-ui-router .
codef0rmer

1
Я использую $routeUpdateсобытие. Я думаю, что $routeChangeStartсрабатывает при переходе в другое место.
lucassp

@kuchumovn: К сожалению, мы все еще находимся в 2014 году. Angular 2.0 будет иметь обновленную маршрутизацию (вероятно, встроенный angular-ui-router), которая будет делать то, что вы планировали.
codef0rmer

1
@ codef0rmer, я не раз встречал этот ответ. Благодаря! Отличный ответ, спустя столько времени!
морозный

9

Вы можете установить для свойства reloadOnSearch $ routeProvider значение false.

Возможный повторяющийся вопрос: можете ли вы изменить путь без перезагрузки контроллера в AngularJS?

С уважением


Похоже, это дубликат. К сожалению, похоже, что у них такая же проблема, поскольку она обновляется, если она является частью пути URL, а не переменной запроса.
Ian Muir

Нет, это не дубликат.
OZ_

Это не дубликат, так как связанный вопрос касается того, чтобы не перезагружать контроллер, а не перезагружать шаблон. Решение связанного вопроса приведет к перезагрузке представления.
Лайош Месарош,


3

Мы используем Angular UI Router вместо встроенных маршрутов для аналогичного сценария. Кажется, что он не создает повторно экземпляр контроллера и повторно отображает все представление.


2
Вы пробовали использовать $state.transitionTo()вместо $location.path()?
DreamSonic

1
Я вообще не меняю $ location.path (), где $state.transitionTo()тогда писать ?
OZ_

Цитата: «Когда пользователь максимизирует виджет, мы обновляем URL-адрес, используя location.path, но это вызывает повторную визуализацию представления». Вместо изменения пути вы должны вызвать, $state.transitionTo()который, в свою очередь, обновит хеш URL-адреса.
DreamSonic

Идея состоит в том, что у вас должно быть два вложенных состояния: одно для вашей информационной панели, а другое для вашего развернутого виджета. Когда вы переходите из родительского состояния в дочернее состояние, будет повторно визуализироваться только дочернее представление, но не родительское представление.
DreamSonic

3

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

Вам не нужно преобразовывать свой путь в строки запроса, если вы используете angular-ui-router .

В настоящее время из-за того, что может рассматриваться как ошибка , установка reloadOnSearch: falseсостояния приведет к возможности изменить маршрут без перезагрузки представления. Пользователь GitHub lmessinger был даже достаточно любезен, чтобы предоставить его демонстрацию. Вы можете найти ссылку из его комментария, указанного выше.

В основном все, что вам нужно сделать, это:

  1. Используйте ui-routerвместоngRoute
  2. В ваших штатах объявите те, которые вы хотите, с reloadOnSearch: false

В моем приложении у меня есть представление списка категорий, из которого вы можете перейти в другую категорию, используя такое состояние:

$stateProvider.state('articles.list', {
  url: '{categorySlug}',
    templateUrl: 'partials/article-list.html',
    controller: 'ArticleListCtrl',
    reloadOnSearch: false
  });

Вот и все. Надеюсь это поможет!


2

Как я это реализовал:
(мое решение в основном для случаев, когда вам нужно изменить весь маршрут, а не его части)

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

  1. выключить $ routeProvider
  2. в контроллере mainPage добавьте два div с настраиваемым атрибутом директивы - каждая директива содержит только 'templateUrl' и 'scope: true'

     <div ng-show="tab=='tab_name'" data-tab_name-page></div>
    
  3. Контроллер mainPage содержит строки для имитации маршрутизации:

    if (!$scope.tab && $location.path()) {
        $scope.tab = $location.path().substr(1);
    }
    $scope.setTab = function(tab) {
        $scope.tab = tab;
        $location.path('/'+tab);
    };
    

Это все. Немного некрасиво иметь отдельную директиву для каждой страницы, но использование динамического templateUrl (как функции) в директиве провоцирует повторный рендеринг страницы (и потерю данных входных данных).


0

Если я правильно понял ваш вопрос, вы хотите,

  1. Разверните виджет, когда пользователь находится на / dashboard /: dashboardId, и он разворачивает виджет до максимума.
  2. Вы хотите, чтобы у пользователя была возможность вернуться в / dashboard /: dashboardId /: maximizedWidgetId и по-прежнему видеть виджет развернутым.

Вы можете настроить только первый маршрут в routerConfig и использовать RouteParams, чтобы определить, передается ли развернутый виджет в params в контроллере этого настроенного маршрута, и максимизировать тот, который передан как param. Если пользователь максимизирует его в первый раз, поделитесь URL-адресом этого развернутого представления с помощью maximizedWidgetId в пользовательском интерфейсе.

Пока вы используете $ location (который является просто оболочкой над собственным объектом местоположения) для обновления пути, он обновит представление.


1
Не только $ location обновит представление. ng-include также будет, даже без изменения $ location.
OZ_

@OZ_ я не предлагал ngInclude , поскольку это просто изменение состояния внутри зрения я просто предполагая , вероятно , что - то вроде нг-если , который будет связан с функцией , которая может выяснить routeParams
Sivakumar Kailasam

0

У меня есть идея использовать

window.history.replaceState ('Объект', 'Название', '/ новый-url');

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

Однако я не проверял это.


-2

Приведенный ниже код позволит вам изменить URL-адрес без перенаправления, например: http: // localhost / # / 691? Foo? Bar? Blabla

for(var i=0;i<=1000;i++) $routeProvider.when('/'+i, {templateUrl: "tabPages/"+i+".html",reloadOnSearch: false});

Но когда вы перейдете на http: // localhost / # / 692 , вы будете перенаправлены.


Я не понимаю, зачем добавлять сюда еще один ответ.
gsamaras

1
это примечание к истории.
abc
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.