Angular2-Router behalten die Abfragezeichenfolge bei

78

Ich habe eine Angular2 (v2.0.1) -Anwendung geschrieben, die den Router verwendet. Die Website wird mit mehreren Abfragezeichenfolgenparametern geladen, sodass die vollständige URL zunächst folgendermaßen aussieht:

https://my.application.com/?param1=val1&param2=val2&param3=val3

In meiner Routenkonfiguration habe ich einen Eintrag, der eine leere Route umleitet:

const appRoutes: Routes = [
    {
        path: '',
        redirectTo: '/comp1',
        pathMatch: 'full'
    },
    {
        path: 'comp1',
        component: FirstComponent
    },
    {
        path: 'comp2',
        component: SecondComponent
    }
];

Mein Problem ist, dass die URL nach dem Booten der App keine Abfrageparameter mehr enthält, sondern wie folgt aussieht:

https://my.application.com/comp1

Gibt es eine Möglichkeit, den Router so zu konfigurieren, dass beim Navigieren die ursprüngliche Abfragezeichenfolge beibehalten wird?

Danke
Lukas

Lukas Kolletzki
quelle

Antworten:

65

Ich glaube nicht, dass es eine Möglichkeit gibt, dies in der Routenkonfiguration zu definieren.

Derzeit wird es unterstützt, damit routerLinks und imperative Navigation aktiviert werden können

Sie können der leeren Pfadroute eine Wache hinzufügen, wobei in der Wache die Navigation zur /comp1Route erfolgt.

router.navigate(['/comp1'], { preserveQueryParams: true }); //deprecated see update note
router.navigate(['/comp1'], { queryParamsHandling: "merge" });

Es gibt eine PR , die die preserveQueryParamsglobale Konfiguration ermöglicht .

Update-Hinweis: In https://angular.io/api/router/NavigationExtras isterveQueryParams veraltet. Verwenden Sie stattdessen queryParamsHandling

Günter Zöchbauer
quelle
1
Wo würde diese Codezeile hinzugefügt werden? Und können Sie "Wache" anhand eines Codebeispiels erklären?
Mattrowsboats
Ich habe dies getan, aber das Hinzufügen eines canActivate-Schutzes zur "Umleitungs" -Route für leere Zeichenfolgen wird nicht übernommen.
Mattrowsboats
2
Ok, aber das Problem besteht weiterhin bei der App-Eingabe. Wenn Sie versuchen, die URL-Parameter zu "fangen", nachdem die App gebootet wurde, ist es zu spät. Sie wurden bereits ausgezogen.
Mattrowsboats
1
Nach langer Zeit stellte ich fest, dass navigateByUrldas nicht funktioniert. Es ist besser, navigateimmer zu verwenden .
Karthik
1
Es tut mir leid, dass ich abgelehnt habe, aber nur die Antwort von AArias hat bei mir funktioniert (Angular 9, falls relevant).
Arnaud P
50

Wenn Sie mit einer HTML-Vorlage navigieren, können Sie diese verwenden

<a [routerLink]="['/page-2']" [routerLinkActive]="['is-active']" queryParamsHandling="merge">

Beachten Sie, dass der Parameter queryParamsHandling ohne eckige Klammern steht.

Kamalpreet
quelle
1
Dies ist die beste Antwort und die Bemerkung über die Klammern hat mir wirklich einige Zeit gespart
leider
Die HTML-Lösung ist das, wonach ich wirklich gesucht habe. Vielen Dank!
Dinesh Shekhawat
17

Es stellt sich heraus, dass der undokumentierte Weg, dies ohne andere Hacks zu tun, darin besteht, einfach den führenden Schrägstrich im Feld "redirectTo" zu entfernen. Da Sie mit dem vollständigen Pfad übereinstimmen, können Sie sicher sein, dass er das tut, was Sie wollen (dh keine überraschenden URL-Segmente), und da es kein absolutes Ziel mehr ist, behält Angular die aktuellen Abfrageparameter bei.

Also in diesem Fall

{
  path: '',
  redirectTo: '/comp1',
  pathMatch: 'full'
}

wird:

{
  path: '',
  redirectTo: 'comp1',
  pathMatch: 'full'
}

Quelle: https://github.com/angular/angular/issues/13315

Christopher
quelle
geschafft! Das ist der einzige Weg
Yazan Khalaileh
einfachste Antwort
Ricardo
12

Die Antwort von Günter Zöchbauer sollte richtig funktionieren, aber aus irgendeinem Grund funktioniert sie bei mir überhaupt nicht. Was am Ende funktionierte, war das queryParamsdirekte Übergeben, anstatt sie zu "bewahren".

So sieht meine Wache aus:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    (...)
    this.router.navigate(['login'], { queryParams: route.queryParams });
}
AArias
quelle
Richtig, diese Antwort war die einzige, die auch für mich funktioniert hat
Arnaud P
3

Möglicherweise möchten Sie https://github.com/angular/angular/issues suchen nach einer ähnlichen Funktionsanforderung . Wenn keine vorhanden ist, senden Sie eine Funktionsanforderung.

In der Zwischenzeit: Ich glaube, Sie müssen eine Komponente auf dem Pfad '' erstellen, mit dem alleinigen Zweck, dann zu '/ comp1' umzuleiten, während die QueryString-Parameter beibehalten werden.

Martin
quelle
Vielen Dank, ich werde mir die Probleme ansehen und bei Bedarf eine einreichen.
Lukas Kolletzki
1

Nachdem ich die meisten Antworten ausprobiert hatte, fand ich das

  • Die Antwort von Günter Zöchbauer funktioniert bei mir überhaupt nicht
  • Christophers Vorschlag, die Führung zu entfernen, /tat es auch nicht
  • Die Antwort von AArias hat funktioniert, führte jedoch zum Hinzufügen von zwei URLs in der Geschichte:
    1. https://my.application.com/comp1?param=val <= (ಠ 益 ಠ)
    2. https://my.application.com/comp1;param=val

Hier ist noch ein weiterer Ansatz, der sich letztendlich gemäß meinen Erwartungen verhalten hat:

import { ActivatedRoute, Router } from '@angular/router';

class Component {
    constructor(private route: ActivatedRoute, private router: Router) {}

    someMethod() {
        router.navigate(['/comp1', this.route.snapshot.params]);
    }
}
Arnaud P.
quelle
0

Wenn Sie mit einer HTML-Vorlage navigieren, können Sie diese auch verwenden preserveQueryParams="true"

Beachten Sie, dass dies preserveQueryParamsohne eckige Klammer ist.

Z.B:

<a [routerLink]="['/navigate-to']" preserveQueryParams="true">

Vandesh
quelle
Laut angular.io/api/router/NavigationExtras preserveQueryParams ist veraltet.
Cezary Tomczyk
0

Es gibt eine Problemumgehung für die Verwendung sekundärer Routen, da Angular diese über die primäre Routennavigation hinweg beibehält.

Fügen Sie zunächst einen benannten Router-Ausgang in Ihre oberste Komponente ein:

<router-outlet name="params"><router-outlet>

Erstellen Sie als Nächstes eine Dummy-Komponente, an die weitergeleitet werden soll:

@Component({
    template: ""
})
export class ParamsComponent {}

und definieren Sie eine Route, um diese Komponente in den genannten Ausgang zu instanziieren:

{
    path: ':val1',
    component: ParamsComponent,
    outlet: "params"
}

Ändern Sie Ihre App-Navigation in:

https://my.application.com/(params:val1)

Wenn Sie sich eine ActivatedRoute ansehen, können Sie die "params" -Route finden, indem Sie:

  var paramsRoute = this.activatedRoute.route.children.find(r => r.outlet == "params");

Wenn paramsRoute null ist, enthält die URL nicht das (params: val1).

Dieser nächste Teil wird etwas "hackig", da die sekundäre Route beim ersten Laden nach der primären Route instanziiert wird. Aus diesem Grund ist paramsRoute.snapshot möglicherweise null, bis Ihre App vollständig geladen ist. Es gibt eine private Eigenschaft "_futureSnapshot", die die Routenparameter beim ersten Start enthält ... und während der gesamten Lebensdauer der App erhalten bleibt. Sie können diese erreichen, indem Sie:

var queryParams = 
      paramsRoute
      ? paramsRoute["_futureSnapshot"].params
      : {};
var val1 = queryParams["val1"];

Da _futureSnapshot nicht Teil der öffentlichen API ist, ist dies wahrscheinlich ein Feld, das wir nicht verwenden sollten. Wenn Sie Schwierigkeiten haben, es zu verwenden, könnten Sie wahrscheinlich paramsRoute.params abonnieren, aber dies wird Ihre Komponenten wahrscheinlich komplizieren.

if (paramsRoute) {
    paramsRoute.params.subscribe(params => {
        this.queryParams = params;
        this.loadData();
    });
} else {
    this.queryParams = {};
    this.loadData();
}

========= ÄNDERUNG ==============

Ich habe einen noch besseren Weg gefunden, um die Abfrageparameter abzurufen, der definitiv NICHT icky ist ... Fügen Sie in einer Komponente oder einem Dienst, der vor dem Routing instanziiert wird, die folgende Logik hinzu:

    const routeRecognizedSubscription = this.router.events
        .filter(e => e instanceof RoutesRecognized)
        .subscribe((e: RoutesRecognized) => {
            const paramsRoute = e.state.root.children.find(r => r.outlet == "params");
            if (paramsRoute) {
                // capture or use paramsRoute.params 
            }
            routeRecognizedSubscription.unsubscribe();
        });

Dieser Code abonniert vorübergehend RoutesRecognized-Ereignisse, die vor der Navigation auftreten. Nachdem das erste Ereignis empfangen wurde, wird es automatisch abgemeldet, da dies nur beim Starten der App erforderlich ist.

Beim ersten Ereignis suchen wir nach dem Status, der dem Ausgang "params" entspricht. Wenn gefunden, enthält die Eigenschaft params die Daten, die wir benötigen. Sie müssen nicht auf private Immobilien zugreifen.

Greg Petrites
quelle