Modifier les paramètres d'itinéraire sans recharger dans Angular 2

114

Je crée un site Web immobilier en utilisant Angular 2, Google Maps, etc. et lorsqu'un utilisateur change le centre de la carte, j'effectue une recherche dans l'API indiquant la position actuelle de la carte ainsi que le rayon. Le fait est que je veux refléter ces valeurs dans l'URL sans recharger la page entière. Est-ce possible? J'ai trouvé des solutions en utilisant AngularJS 1.x mais rien à propos d'Angular 2.

Marcos Basualdo
la source
Je pense que si vous utilisez [routerLink] = "['/ route', {param1: value1}] il ne rechargera pas la page
Toolkit
mais comment puis-je ajouter un autre paramètre de requête?
Toolkit
2
☝️ cela provoquera un rechargement de page
LifterCoder
Notez simplement que si vous utilisez SSR pour rendre votre site compatible avec le référencement, il s'agit d'un problème théorique.
Jonathan
@Jonathan, c'est ça? Étant donné qu'Angular prend en charge le routage une fois la page statique rendue, je pense que c'est toujours une question valable même lors de l'utilisation de SSR.
adam0101 du

Réponses:

92

Vous pouvez utiliser location.go(url)ce qui changera fondamentalement votre URL, sans changement de route d'application.

REMARQUE cela pourrait provoquer d'autres effets comme la redirection vers la route enfant à partir de la route actuelle.

Question connexe qui décritlocation.gone sera pas intime deRouterse produire des changements.

Pankaj Parkar
la source
2
Mon itinéraire a un paramètre nommé 'search' dans lequel un reçoit une version sérialisée des champs de recherche, lorsque l'état de la liste se charge pour la première fois, je ne lis ces paramètres qu'en utilisant this._routeParams.get ('search'), désérialise les filtres et effectuez la recherche. Si l'utilisateur modifie les champs de recherche, soit en utilisant la carte ou les facettes de recherche, je construis simplement l'URL correcte en utilisant la méthode generate du routeur var instruction = this._router.generate (['Listing', {search: serializedFields}] ) puis en utilisant this._location.go (instruction.urlPath) pour modifier l'url sans recharger l'état.
Marcos Basualdo
20
Si quelqu'un d'autre se demande: importez {Location} depuis 'angular2 / platform / common';
Kesarion
18
import { Location } from '@angular/common';dans Angular 4
tehCivilian
2
Avez-vous decared constructr likeconstructor(private location: Location){ }
Pankaj Parkar
2
@AdrianE le problème est très probablement que vous avez tapé location.go()alors que vous auriez dû taper this.location.go(). Lorsque vous émettez le this., vous appelez l'interface de localisation de Typescript.
georg-un
94

À partir de RC6, vous pouvez effectuer les opérations suivantes pour modifier l'URL sans changer d'état et ainsi conserver l'historique de votre itinéraire

    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/");
        }
    }
tjuzbumz
la source
Cela ne fonctionne pas pour moi. Il essaie toujours de charger l'itinéraire. Erreur de console:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Inigo
2
Combinez cela avec la création d'URL comme suggéré par @golfadas et nous avons un gagnant!
crowmagnumb
63

L'utilisation location.go(url)est la voie à suivre, mais au lieu de coder en dur l'URL, envisagez de la générer en utilisant router.createUrlTree().

Étant donné que vous souhaitez effectuer l'appel de routeur suivant: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})mais sans recharger le composant, il peut être réécrit comme:

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

 this.location.go(url);
golfadas
la source
9
Cette réponse a résolu mon problème. Une question, l'url générée ci-dessus a des paramètres délimités par ";" (point-virgule). Que devons-nous faire pour séparer chaque paramètre de la requête par "&"?
Amarnath
2
c'est la déclaration de createUrlTree (commandes: any [], navigationExtras ?: NavigationExtras). vous devez utiliser queryParams situé navigationExtras pas commads. createUrlTree ([], {relativeTo: this.activatedRoute, queryParams: {param: 1}})
kit
juste pour clarifier ce que @kit a dit, faites ceci:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
bluegrounds
12

Pour quiconque comme moi trouve cette question, ce qui suit pourrait être utile.

J'ai eu un problème similaire et j'ai d'abord essayé d'utiliser location.go et location.replaceState comme suggéré dans d'autres réponses ici. Cependant, j'ai rencontré des problèmes lorsque je devais naviguer vers une autre page de l'application car la navigation était relative à l'itinéraire actuel et l'itinéraire actuel n'était pas mis à jour par location.go ou location.replaceState (le routeur ne sait rien sur ce qu'ils font à l'URL)

En substance, j'avais besoin d'une solution qui ne rechargeait pas la page / le composant lorsque le paramètre d'itinéraire était modifié, mais DID mettait à jour l'état de l'itinéraire en interne.

J'ai fini par utiliser des paramètres de requête. Vous pouvez en savoir plus ici: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

Donc, si vous devez faire quelque chose comme enregistrer une commande et obtenir un identifiant de commande, vous pouvez mettre à jour l'URL de votre page comme indiqué ci-dessous. La mise à jour d'un emplacement de centre et des données associées sur une carte serait similaire

// 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.
}

et vous en gardez une trace dans la méthode ngOnInit comme:

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]
}

Si vous devez accéder directement à la page de commande avec une nouvelle commande (non enregistrée), vous pouvez faire:

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

Ou si vous devez accéder directement à la page de commande pour une commande existante (enregistrée), vous pouvez faire:

this.router.navigate(['orders'], { queryParams: { id: '1234' } });
TornadeAli
la source
10

J'ai eu du mal à faire fonctionner cela dans les versions RCx d'angular2. Le package Location a été déplacé et l'exécution de location.go () à l'intérieur de constructor () ne fonctionnera pas. Il doit être ngOnInit () ou plus tard dans le cycle de vie. Voici un exemple de code:

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

Voici les ressources angulaires en la matière: https://angular.io/docs/ts/latest/api/common/index/Location-class.html https://angular.io/docs/ts/latest/api/ common / index / LocationStrategy-class.html

Luke Dupin
la source
7

J'utilise cette façon de l'obtenir:

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()
);

-- ÉDITER --

Je pense que je devrais ajouter quelques informations supplémentaires pour cela.

Si vous utilisez le this.location.replaceState()routeur de votre application n'est pas mis à jour, donc si vous utilisez les informations du routeur plus tard, ce n'est pas la même chose dans votre navigateur. Par exemple, si vous utilisez localizeServicepour changer de langue, après avoir changé de langue, votre application revient à la dernière URL où vous étiez avant de la changer avec this.location.replaceState().

Si vous ne voulez pas ce comportement, vous pouvez choisir une méthode différente pour mettre à jour l'URL, comme:

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

Dans cette option, votre navigateur ne s'actualise pas non plus, mais votre URLmodification est également injectée dans Routervotre application, donc lorsque vous changez de langue, vous n'avez pas de problème comme dans this.location.replaceState().

Bien sûr, vous pouvez choisir la méthode pour vos besoins. Le premier est plus léger car vous n'engagez pas plus votre application que le changement URLde navigateur.

kris_IV
la source
3

Pour moi, c'était en fait un mélange des deux avec Angular 4.4.5.

L'utilisation de router.navigate a continué à détruire mon url en ne respectant pas la partie realtiveTo: enabledRoute.

J'ai fini avec:

this._location.go(this._router.createUrlTree([this._router.url], { queryParams: { profile: value.id } }).toString())
Patrick P.
la source
3

Utilisez l'attribut queryParamsHandling: 'merge' lors de la modification de l'url.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});
Rajeev Raushan Prasad
la source
3
Cela provoque le rechargement du composant actuellement acheminé
btx