Aktualizowanie adresu URL w Angular JS bez ponownego renderowania widoku


79

Buduję system pulpitów nawigacyjnych w AngularJS i mam problem z ustawieniem adresu URL przez $location.path

W naszym panelu mamy kilka widżetów. Każdy z nich pokazuje większy, zmaksymalizowany widok po kliknięciu. Próbujemy skonfigurować głębokie linki, aby umożliwić użytkownikom łączenie się z pulpitem nawigacyjnym z zmaksymalizowanym widżetem.

Obecnie mamy 2 trasy, które wyglądają jak /dashboard/:dashboardIdi/dashboard/:dashboardId/:maximizedWidgetId

Gdy użytkownik maksymalizuje widżet, aktualizujemy jego adres URL za pomocą $location.path, ale powoduje to ponowne renderowanie widoku. Ponieważ mamy wszystkie dane, nie chcemy przeładowywać całego widoku, chcemy tylko zaktualizować URL. Czy istnieje sposób na ustawienie adresu URL bez powodowania ponownego renderowania widoku?

HTML5Modejest ustawiony na true.


1
Jeśli chcesz, aby Twoje dane przetrwały zmiany tras po stronie klienta, dlaczego nie przekazać ich do usługi?
Riko

Odpowiedzi:


133

W rzeczywistości widok będzie renderowany za każdym razem, gdy zmienisz adres URL. Tak właśnie działa $ routeProvider w Angular, ale można go przekazać maximizeWidgetIdjako obiekt typu querystring, który nie renderuje ponownie widoku.

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

Gdy klikniesz widżet, aby zmaksymalizować:

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

Adres URL w pasku adresu zmieniłby się na http://app.com/dashboard/1?maximizeWidgetId=1

Możesz nawet obserwować, gdy wyszukiwanie zmienia się w adresie URL (z jednego widżetu na inny)

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

1
Jeśli odpowiedź zostanie zaakceptowana, utworzę oddzielne pytanie bez żadnych elementów ": param". Po prostu głupie pytanie: jak nie renderować ponownie widoku.
OZ_

2
Myślę, że router angular-ui będzie w tym przypadku oczywistym wyborem.
codef0rmer

1
Korzystam z $routeUpdatewydarzenia. Myślę, że $routeChangeStarturuchamia się, gdy przenosisz się do innej lokalizacji.
lucassp

@kuchumovn: Niestety nadal jesteśmy w 2014 roku. Angular 2.0 będzie miał odnowiony routing (prawdopodobnie wbudowany router angular-ui-router), który będzie robił to, co zamierzałeś.
codef0rmer

1
@ codef0rmer, znalazłem tę odpowiedź więcej niż raz. Dzięki! Świetna odpowiedź, wciąż po tak długim czasie!
mroźny

9

Możesz ustawić właściwość reloadOnSearch elementu $ routeProvider na wartość false.

Możliwe zduplikowane pytanie: czy możesz zmienić ścieżkę bez ponownego ładowania kontrolera w AngularJS?

pozdrowienia


Wygląda na to, że jest to duplikat. Niestety wygląda na to, że mają ten sam problem, o ile jest to część ścieżki adresu URL, a nie zmienna zapytania, odświeża się.
Ian Muir

Nie, to nie jest duplikat.
OZ_

To nie jest duplikat, ponieważ połączone pytanie dotyczy nie ponownego ładowania kontrolera i nie ponownego ładowania szablonu. Rozwiązanie w powiązanym pytaniu spowoduje ponowne załadowanie widoku.
Lajos Meszaros


3

Używamy routera Angular UI zamiast wbudowanych tras w podobnym scenariuszu. Nie wydaje się, aby ponownie tworzył instancję kontrolera i ponownie renderował cały widok.


2
Czy próbowałeś używać $state.transitionTo()zamiast $location.path()?
DreamSonic

1
W ogóle nie zmieniam $ location.path (), gdzie w takim razie należy napisać $state.transitionTo()?
OZ_

Cytat: „Gdy użytkownik maksymalizuje widget, aktualizujemy jego adres URL przy użyciu metody location.path, ale powoduje to ponowne renderowanie widoku”. Zamiast zmieniać ścieżkę, powinieneś zadzwonić, $state.transitionTo()co z kolei zaktualizuje hash adresu URL.
DreamSonic

Chodzi o to, że powinieneś mieć dwa zagnieżdżone stany: jeden dla pulpitu nawigacyjnego i jeden dla zmaksymalizowanego widżetu. Podczas przechodzenia ze stanu nadrzędnego do stanu podrzędnego zostanie ponownie wyrenderowany tylko widok podrzędny, a nie widok nadrzędny.
DreamSonic

3

Zdaję sobie sprawę, że to stare pytanie, ale ponieważ znalezienie odpowiedzi zajęło mi półtora dnia, więc proszę.

Jeśli używasz angular-ui-router, nie musisz konwertować ścieżki na ciągi zapytań .

Obecnie, z powodu tego, co można uznać za błąd , ustawienie reloadOnSearch: falsestanu spowoduje możliwość zmiany trasy bez ponownego ładowania widoku. Użytkownik GitHub, lmessinger, był nawet na tyle uprzejmy, aby udostępnić jego wersję demonstracyjną. Możesz znaleźć link z jego komentarza, do którego link znajduje się powyżej.

Zasadniczo wszystko, co musisz zrobić, to:

  1. Użyj ui-routerzamiastngRoute
  2. W swoich stanach deklarujcie, z którymi chcecie reloadOnSearch: false

W mojej aplikacji mam widok listy kategorii, z którego można przejść do innej kategorii, używając takiego stanu:

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

Otóż ​​to. Mam nadzieję że to pomoże!


2

Jak to zaimplementowałem:
(moje rozwiązanie głównie w przypadkach, gdy trzeba zmienić całą trasę, a nie jej części)

Mam stronę z menu (menuPage) i dane nie powinny być czyszczone w nawigacji (na każdej stronie jest dużo danych wejściowych i użytkownik będzie bardzo niezadowolony, jeśli dane znikną przypadkowo).

  1. wyłącz $ routeProvider
  2. w kontrolerze mainPage dodaj dwa elementy div z atrybutem dyrektywy niestandardowej - każda dyrektywa zawiera tylko „templateUrl” i „scope: true”

     <div ng-show="tab=='tab_name'" data-tab_name-page></div>
    
  3. Kontroler mainPage zawiera linie symulujące routing:

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

To wszystko. Trochę brzydko jest mieć osobną dyrektywę dla każdej strony, ale użycie dynamicznego templateUrl (jako funkcji) w dyrektywie powoduje ponowne renderowanie strony (i utratę danych wejściowych).


0

Jeśli dobrze zrozumiałem twoje pytanie, chcesz,

  1. Zmaksymalizuj widżet, gdy użytkownik jest w / dashboard /: dashboardId i maksymalizuje widżet.
  2. Chcesz, aby użytkownik mógł wrócić do / dashboard /: dashboardId /: maximizedWidgetId i nadal widzieć zmaksymalizowany widżet.

Możesz skonfigurować tylko pierwszą trasę w konfiguracji routera i użyć RouteParams do określenia, czy zmaksymalizowany widżet jest przekazywany w parametrach w kontrolerze tej skonfigurowanej trasy i zmaksymalizować tę przekazaną jako parametr. Jeśli użytkownik maksymalizuje go za pierwszym razem, udostępnij adres URL do tego zmaksymalizowanego widoku za pomocą maximizedWidgetId w interfejsie użytkownika.

Dopóki używasz $ location (który jest po prostu opakowaniem na natywnym obiekcie lokalizacji) do aktualizacji ścieżki, odświeży widok.


1
Nie tylko $ location odświeży widok. ng-include będzie również, nawet bez zmiany $ location.
OZ_

@OZ_ Nie sugerowałem ngInclude, ponieważ jest to tylko zmiana stanu w widoku. Sugeruję tylko prawdopodobnie coś w rodzaju ng-if, które byłoby powiązane z funkcją, która może obliczyć routeParams
Sivakumar Kailasam

0

Mam pomysł do wykorzystania

window.history.replaceState ('Obiekt', 'Tytuł', '/ nowy-url');

Jeśli to zrobisz i nastąpi cykl trawienia, to całkowicie wszystko zepsuje. Jeśli jednak ustawisz go z powrotem na prawidłowy adres URL, który oczekuje, że angular jest w porządku. Więc teoretycznie możesz zapisać poprawny adres URL, którego oczekuje angular i zresetować go tuż przed uruchomieniem skrótu.

Jednak nie testowałem tego.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.