How to set default query params for Route in Angular 7?

10,947

In our Angular-7-Application, we use @ngrx and @ngrx/router-store to get the query params into the state.

To have query params and state synchronized you need an effect that captures any action that results in a page change in your application. Inside the event, you'll have something like:

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

Then have a meta reducer to update state from query params on page reload:

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

This way you always know if page number changes it's gonna be reflected in url consequently. So even if you go to a new route(component) after that route gets its initial data the effect will trigger which updates query params.

You may want to checkout out this phenomenal article about state management in angular apps

Share:
10,947
Florian Gössele
Author by

Florian Gössele

"We are what we repeatedly do. Excellence, then, is not an act but a habit." - Aristotle

Updated on June 08, 2022

Comments

  • Florian Gössele
    Florian Gössele almost 2 years

    In our Angular-7-Application, we use @ngrx and @ngrx/router-store to get the query params into the state.

    A few components of the application are paginated lists. We have every list as a component and the Pagination-Component included in every list.

    The current page is stored in the URL as a query Parameter: user/:userId/agent?page=0 and the PaginationComponent gets the current page from state.router.state.queryParams.page. However, if a user accesses the URL user/:userId/agent, queryParams.page returns undefined.

    We could solve this by using state.router.state.queryParams.page || 0 in every component but I wonder, if there is an easier way - can a Route without query params be redirect to a Route with query params?

    I tried using the most obvious redirect:

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

    but I get Error: Cannot match any routes. URL Segment: 'user/max/agent'.

    The only feature request I found was this one where the error above appears.

  • david_i_smith
    david_i_smith over 4 years
    Thanks for the link to that article. The following made me wonder whether the navigation should take place inside the effect or outside: "Since the user can always interact with the URL directly, we should treat the router as the source of truth and the initiator of actions."