In unserer Angular-7-Anwendung verwenden wir @ngrx und @ ngrx / router-store, um die Abfrageparameter in den Status zu versetzen.

Einige Komponenten der Anwendung sind paginierte Listen. Wir haben jede Liste als Komponente und die Paginierungskomponente in jeder Liste enthalten.

Die aktuelle Seite wird in der URL als Abfrageparameter gespeichert: user/:userId/agent?page=0 und die PaginationComponent erhält die aktuelle Seite von state.router.state.queryParams.page. Wenn ein Benutzer jedoch auf die URL user/:userId/agent zugreift, gibt queryParams.page undefiniert zurück.

Wir könnten dies lösen, indem wir state.router.state.queryParams.page || 0 in jeder Komponente verwenden, aber ich frage mich, ob es einen einfacheren Weg gibt - kann eine Route ohne Abfrageparameter zu einer Route mit Abfrageparametern umgeleitet werden?

Ich habe versucht, die offensichtlichste Weiterleitung zu verwenden:

{ path: 'user/:userId/agent', redirectTo: '/user/:userId/agent?page=0', pathMatch: 'full' },
{ path: 'user/:userId/agent?page=0', component: AgentListComponent },

Aber ich bekomme Error: Cannot match any routes. URL Segment: 'user/max/agent'.

Die einzige Feature-Anfrage, die ich gefunden habe, war diese, bei der der obige Fehler auftritt.

4
Florian Gössele 19 Jän. 2019 im 17:34

3 Antworten

Beste Antwort

Für Ihre Frage speziell:

Kann eine Route ohne Abfrageparameter zu einer Route mit Abfrageparametern umgeleitet werden?

Ich glaube nicht, dass das funktionieren kann, weil das? In einer Abfrage befindet sich ein Trennzeichen, das nicht Teil der Abfragezeichenfolge einer URL ist.

Alternative 1 - Da Sie ngrx verwenden, können Sie dies auch mit dem benutzerdefinierten Serializer tun. Die Dokumente auf der Website ngrx.io zeigen eine Beispiel für die Rückgabe der Parameter mit Serialisierung. Hier können Sie Logik hinzufügen, um den Parametern einen Standard hinzuzufügen, falls dieser nicht vorhanden ist. Ich lehne ab, dass dies möglicherweise weniger ideal ist, da es auf jeder Route ausgelöst wird, aber es kann Ihre Routen einfacher machen.

import { Params, RouterStateSnapshot } from '@angular/router';
import { RouterStateSerializer } from '@ngrx/router-store';

export interface RouterStateUrl {
  url: string;
  params: Params;
  queryParams: Params;
}

export class CustomSerializer implements RouterStateSerializer<RouterStateUrl> {
  serialize(routerState: RouterStateSnapshot): RouterStateUrl {
    let route = routerState.root;

    while (route.firstChild) {
      route = route.firstChild;
    }

    const {
      url,
      root: { queryParams },
    } = routerState;
    const { params } = route;

    // Add here
    if (<insert url logic> && queryParams.page === undefined) {
        queryParams.page = 0;
    }

    // Only return an object including the URL, params and query params
    // instead of the entire snapshot
    return { url, params, queryParams };
  }
}

Alternative 2 - Sie können den HttpClient umschließen oder vorzugsweise eine generische Seitenlistenmethode erstellen, die dies überprüft und der Anforderung hinzufügt, wenn keine Seite vorhanden ist. Diese Antwort zeigt ein Beispiel für das Hinzufügen von Parametern.

Alternative 3 - Sie können die Seite als Teil des Pfads verwenden und nach Bedarf Umgehungen / Änderungen vornehmen, um Ihre Anforderungen zu generieren.

{ path: 'user/:userId/agent', redirectTo: '/user/:userId/agent/0', pathMatch: 'full' },
{ path: 'user/:userId/agent/:page', component: AgentListComponent },
3
user10747134user10747134 19 Jän. 2019 im 15:47

In unserer Angular-7-Anwendung verwenden wir @ngrx und @ ngrx / router-store, um die Abfrageparameter in den Status zu versetzen.

Um Abfrageparameter und Status synchronisieren zu können, benötigen Sie einen Effekt, der alle Aktionen erfasst, die zu einer Seitenänderung in Ihrer Anwendung führen. Innerhalb der Veranstaltung haben Sie so etwas wie:

@Effect({dispatch:false})
setRouteParams = this.actions$.pipe(
    ofType<ActionCausingPageChange>("action name"),
    tap( action =>{

        let a = { page: action.payload.page };
        // or in case it's not part of action payload, get it from store
        this.router.navigate(
            [], {
                relativeTo: this.route,
                queryParamsHandling: 'merge',
                queryParams: a
            });
        }
    )
);

Lassen Sie dann einen Meta-Reduzierer den Status der Abfrageparameter beim erneuten Laden der Seite aktualisieren:

export function initStateFromQueryParams(
    reducer: ActionReducer<AppState>
): ActionReducer<AppState> {
    return function(state, action) {
        const newState = reducer(state, action);
        if ([INIT.toString(), UPDATE.toString()].includes(action.type)) {
            const urlParams = new URLSearchParams(window.location.search);
            return { ...newState, page: urlParams.get("page") };
        }
        return newState;
    };
}

Auf diese Weise wissen Sie immer, wenn sich die Seitenzahl ändert, wird dies folglich in der URL wiedergegeben. Selbst wenn Sie zu einer neuen Route (Komponente) wechseln, nachdem diese Route ihre ursprünglichen Daten erhalten hat, wird der Effekt ausgelöst, der die Abfrageparameter aktualisiert.

Vielleicht möchten Sie diesen phänomenalen Artikel über die Statusverwaltung lesen in eckigen Apps

1
Wildhammer 17 Mai 2019 im 16:51

Für mich hat das auf dem Root-Pfad funktioniert:

{
  path: '',
  redirectTo: '/foo?bar=baz',
  pathMatch: 'full'
}

Wenn Sie dasselbe mit einem benannten Parameter (wie Ihrem :userId) versuchen, funktioniert dies jedoch nicht

0
Ronin 15 Aug. 2019 im 07:57