Изменить параметры маршрута без перезагрузки в Angular 2

115

Я создаю веб-сайт по недвижимости, используя Angular 2, Google Maps и т. Д., И когда пользователь меняет центр карты, я выполняю поиск в API, указывая текущее положение карты, а также радиус. Дело в том, что я хочу отразить эти значения в URL-адресе без перезагрузки всей страницы. Это возможно? Я нашел несколько решений с использованием AngularJS 1.x, но ничего не про Angular 2.

Маркос Басуальдо
источник
Я думаю, что если вы используете [routerLink] = "['/ route', {param1: value1}], он не будет перезагружать страницу
Toolkit
но как я могу добавить еще один параметр запроса?
Toolkit
2
☝️ это вызовет перезагрузку страницы
LifterCoder
Замечу, что если вы используете SSR, чтобы сделать свой сайт SEO-совместимым, это спорная проблема.
Джонатан
@ Джонатан, да? Поскольку Angular берет на себя маршрутизацию после рендеринга статической страницы, я думаю, что это все еще актуальный вопрос даже при использовании SSR.
adam0101

Ответы:

92

Вы можете использовать, location.go(url)который в основном изменит ваш URL-адрес без изменения маршрута приложения.

ПРИМЕЧАНИЕ. Это может вызвать другой эффект, например перенаправление на дочерний маршрут с текущего маршрута.

Связанный с этим вопрос, который описываетlocation.go, не предполагаетRouterизменений.

Панкадж Паркар
источник
2
У моего маршрута есть параметр с именем 'search', в котором я получаю сериализованную версию полей поиска, когда состояние листинга загружается впервые, я только читаю эти параметры, используя this._routeParams.get ('search'), десериализуйте фильтры и выполните поиск. Если пользователь изменяет поля поиска, используя карту или фасеты поиска, я просто создаю правильный URL-адрес, используя метод generate маршрутизатора varstruction = this._router.generate (['Listing', {search: serializedFields}] ), а затем с помощью this._location.go (struction.urlPath) изменить URL-адрес без перезагрузки состояния.
Маркос Басуальдо,
20
Если кому-то еще интересно: импортируйте {Location} из 'angular2 / platform / common';
Кесарион
18
import { Location } from '@angular/common';в Angular 4
tehCivilian
2
Ты решился на конструктора какconstructor(private location: Location){ }
Панкай Паркар
2
@AdrianE проблема, скорее всего, в том, что вы печатали, location.go()а должны были печатать this.location.go(). Когда вы испускаете this., вы вызываете интерфейс местоположения Typescript.
georg-un
96

Начиная с RC6, вы можете сделать следующее, чтобы изменить URL без изменения состояния и тем самым сохранить историю вашего маршрута

    import {OnInit} from '@angular/core';

    import {Location} from '@angular/common'; 
    // If you dont import this angular will import the wrong "Location"

    @Component({
        selector: 'example-component',
        templateUrl: 'xxx.html'
    })
    export class ExampleComponent implements OnInit {
        
        constructor( private location: Location )
        {}

        ngOnInit() {    
            this.location.replaceState("/some/newstate/");
        }
    }
тюцбумз
источник
У меня это не работает. Ситлл пытается загрузить маршрут. Ошибка консоли:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Иниго
2
Объедините это с созданием URL-адреса, как предлагает @golfadas, и у нас есть победитель!
Crowmagnumb
63

Использование location.go(url)- это путь, но вместо жесткого кодирования URL-адреса рассмотрите возможность его создания с помощью router.createUrlTree().

Учитывая, что вы хотите выполнить следующий вызов маршрутизатора: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})но без перезагрузки компонента, его можно переписать как:

const url = this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()

 this.location.go(url);
Golfadas
источник
9
Этот ответ решил мою проблему. Один вопрос, созданный выше URL-адрес имеет параметры, разделенные ";" (точка с запятой). Что нам делать, чтобы разделить каждый параметр в запросе знаком «&»?
Амарнатх
2
это объявление createUrlTree (команды: any [], navigationExtras ?: NavigationExtras). вам нужно использовать queryParams, расположенный navigationExtras, а не коммиты. createUrlTree ([], {relativeTo: this.activatedRoute, queryParams: {param: 1}})
комплект
просто чтобы прояснить, что сказал @kit, сделайте следующее:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
bluegrounds
12

Для тех, кто, как я, нашел этот вопрос, может быть полезно следующее.

У меня была аналогичная проблема, и я сначала пытался использовать location.go и location.replaceState, как это предлагается в других ответах здесь. Однако у меня возникли проблемы, когда мне пришлось перейти на другую страницу в приложении, потому что навигация была относительно текущего маршрута, а текущий маршрут не обновлялся с помощью location.go или location.replaceState (маршрутизатор ничего не знает о том, что они делают с URL-адресом)

По сути, мне нужно было решение, которое НЕ перезагружало страницу / компонент при изменении параметра маршрута, но DID обновляло состояние маршрута внутри.

В итоге я использовал параметры запроса. Вы можете найти больше об этом здесь: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

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

// let's say we're saving an order. Initally the URL is just blah/orders
save(orderId) {
    // [Here we would call back-end to save the order in the database]

    this.router.navigate(['orders'], { queryParams: { id: orderId } });
    // now the URL is blah/orders?id:1234. We don't reload the orders
    // page or component so get desired behaviour of not seeing any 
    // flickers or resetting the page.
}

и вы отслеживаете это в методе ngOnInit, например:

ngOnInit() {
    this.orderId = this.route
        .queryParamMap
        .map(params => params.get('id') || null);
    // orderID is up-to-date with what is saved in database now, or if
    // nothing is saved and hence no id query paramter the orderId variable
    // is simply null.
    // [You can load the order here from its ID if this suits your design]
}

Если вам нужно перейти прямо на страницу заказа с новым (несохраненным) заказом, вы можете сделать:

this.router.navigate(['orders']);

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

this.router.navigate(['orders'], { queryParams: { id: '1234' } });
ТорнадоАли
источник
10

У меня были серьезные проблемы с тем, чтобы заставить это работать в версиях RCx angular2. Пакет Location перемещен, и выполнение location.go () внутри constructor () не будет работать. Это должно быть ngOnInit () или позже в жизненном цикле. Вот пример кода:

import {OnInit} from '@angular/core';
import {Location} from '@angular/common';

@Component({
  selector: 'example-component',
  templateUrl: 'xxx.html'
})
export class ExampleComponent implements OnInit
{
  constructor( private location: Location )
  {}

  ngOnInit()
  {    
    this.location.go( '/example;example_param=917' );
  }
}

Вот ресурсы angular по этому вопросу: https://angular.io/docs/ts/latest/api/common/index/Location-class.html https://angular.io/docs/ts/latest/api/ общий / index / LocationStrategy-class.html

Люк Дюпен
источник
7

Я использую такой способ получения:

const queryParamsObj = {foo: 1, bar: 2, andThis: 'text'};

this.location.replaceState(
  this.router.createUrlTree(
    [this.locationStrategy.path().split('?')[0]], // Get uri
    {queryParams: queryParamsObj} // Pass all parameters inside queryParamsObj
  ).toString()
);

-- РЕДАКТИРОВАТЬ --

Думаю, для этого мне нужно добавить еще немного информации.

Если вы используете this.location.replaceState()маршрутизатор, ваше приложение не обновляется, поэтому, если вы используете информацию о маршрутизаторе позже, это не равноценно этому в вашем браузере. Например, если вы используете localizeServiceдля изменения языка, после переключения языка ваше приложение возвращается к последнему URL-адресу, где вы были до этого, измените его с помощью this.location.replaceState().

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

this.router.navigate(
  [this.locationStrategy.path().split('?')[0]],
  {queryParams: queryParamsObj}
);

В этом варианте ваш браузер также не обновляется, но ваши URLизменения также вводятся в Routerваше приложение, поэтому при переключении языка у вас не возникает проблем, как в this.location.replaceState().

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

kris_IV
источник
3

Для меня это была смесь того и другого с Angular 4.4.5.

Использование router.navigate продолжало уничтожать мой URL-адрес, не соблюдая часть realtiveTo: activateRoute.

Я получил:

this._location.go(this._router.createUrlTree([this._router.url], { queryParams: { profile: value.id } }).toString())
Патрик П.
источник
3

Используйте атрибут queryParamsHandling: 'merge' при изменении URL-адреса.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});
Раджив Раушан Прасад
источник
3
Это вызывает перезагрузку текущего маршрутизируемого компонента
btx