Robert Davey
Robert Davey

Reputation: 291

Change a single route parameter on the current route in Angular 2

Is it possible to change a single route parameter in the current route, while keeping all the other parameters? This is for use in a paging component, which will route to a new page while keeping the other parts of the current route the same.

Some examples:

I have tried using a routerLink, however this loses any additional parameters that are not originally part of the router link.

I have also tried using the current Router to get an Instruction for the current path, however changing the parameters of the Instruction does not seem to have any effect when calling navigateByInstruction().

Upvotes: 29

Views: 16318

Answers (6)

Abanoub Hany
Abanoub Hany

Reputation: 656

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

this.router.navigate(['./'],{relativeTo: this.route, queryParams:  {key:"value"});

Upvotes: 2

Steve Nginyo
Steve Nginyo

Reputation: 301

use if statement or switch case to push parameters

if(yourchild == child1){
    params = { 
      parameter1: parameter1, 
      parameter2: parameter2,
    }
} else (yourchild == child2){
    params = { 
      parameter1: parameter1, 
      parameter2: parameter2,
      parameter3: parameter3
    }
}
this.router.navigate([`/yourparent/${yourchild}`], { queryParams: params });

Upvotes: 0

Kjeld Poulsen
Kjeld Poulsen

Reputation: 243

I would be nice if the activeRoute could return a simple clone of the current route [] to be manipulated before call to router.navigate(nextroutearray), but i did not find such method in the api.

I therefore centralized the requirement into a simple service, where i can parse the current activeRoute, + a set of parameters to be used for the next route. I do not think this code will cover all the complexity of the url in a route, but in my case, I only use parameters on the last part of the route, so it works for me:

The service method looks like this:

routeFor(activeRoute: ActivatedRoute, params: any): any[] {
    let result = [];
    result.push('/');
    for (var i = 0; i < activeRoute.pathFromRoot.length; i++) {
        activeRoute.pathFromRoot[i].snapshot.url.forEach(r => result.push(r.path));
    }

    let currentParams = activeRoute.pathFromRoot[activeRoute.pathFromRoot.length - 1].snapshot.url[0].parameters;
    for (var n in currentParams) {
        if (currentParams.hasOwnProperty(n) && !params.hasOwnProperty(n)) {
            params[n] = currentParams[n];
        }
    }

    result.push(params);
    return result;
}

Then i can use this method in any component getting my sitemap service injected:

setNextTab(tab: string) {
    let nextUrl = this.sitemapService.routeFor(this.activatedRoute, { pagetab: tab });
    this.router.navigate(nextUrl);
}

And in the html, the link to setNextTab method looks like this:

<li (click)="setNextTab('myTabName')">Next tab</li>

Upvotes: 3

Sunil Kumar
Sunil Kumar

Reputation: 859

you can use query parameter option instead of parameter it is use like

in calling component

const navigationExtras: NavigationExtras = {
  queryParams: { 'param_id': 1, 'param_ids': 2, 'list':[1,2,3] },
};
this.router.navigate(['/path'], navigationExtras);

in the called component

  this.route.queryParamMap.map(params =>  params.get('param_id') || 
    'None').subscribe(v => console.log(v));
  this.route.queryParamMap.map(params =>  params.get('param_ids') || 
        'None').subscribe(v => console.log(v));
  this.route.queryParamMap.map(params =>  params.getAll('list') || 
            'None').subscribe(v => console.log(v));

Upvotes: 2

Kesarion
Kesarion

Reputation: 2848

It's quite easy. Let's say we have a method in our ListComponent that changes the page and keeps all other parameters intact (like search related parameters - can't change the page and forget we were searching for something:):

page (page) {
    this.list.page = page;
    this._router.navigate([this.list.route, _.assign(this._params.params, { page: page })]);
    this.update(); // Update your list of items here
}

I used Underscore to assign a page parameter to the existing map of parameters from my private, injected RouteParams object. That map is updated on navigate so we're all good, just remember you can't change it directly, it's imutable.

Here is my implementation of a list of articles along with a pagination component used as a directive to provide pagination:

ArticleListComponent:

@Component({
    selector: 'articles',
    templateUrl: './article/list/index.html',
    directives: [PaginationComponent],
    providers: [ArticleService]
})
export class ArticleListComponent implements OnInit {
    list: ArticleList = new ArticleList;

    private _urlSearchParams: URLSearchParams = new URLSearchParams;

    constructor (
        private _article: ArticleService,
        private _router: Router,
        private _params: RouteParams,
        private _observable: ObservableUtilities
    ) {}

    update () {
        this._observable.subscribe(this._article.retrieveRange(this.list));
    }

    ngOnInit () {
        let page = this._params.get("page");
        if(page) {
            this.list.page = Number(page);
        }

        // check for size in cookie 'articles-per-page'

        let title = this._params.get("title");
        if (title) {
            this.list.title = title;
        }

        this.update();
    }

    size (size: number) {
        // set cookie 'articles-per-page'
    }

    page (page) {
        this.list.page = page;
        this._router.navigate([this.list.route, _.assign(this._params.params, { page: page })]);
        this.update();
    }

    search () {
        this.list.page = 1;
        let params = _.pick({
            title: this.list.title
        }, _.identity);
        this._router.navigate([this.list.route, params ]);
    }
}

PaginationComponent:

import { Component, Input, Output, EventEmitter, OnInit } from 'angular2/core';
import { RouteParams } from 'angular2/router';
import  _ from 'underscore';

import { List } from '../common/abstract';

@Component({
    selector: 'pagination',
    templateUrl: './pagination/index.html'
})
export class PaginationComponent implements OnInit {
    @Input() list: List;
    @Output() change  = new EventEmitter<number>();

    pages: Array<number> = [];

    constructor(
        private _params: RouteParams
    ) {}

    ngOnInit () {
        this.pages = _.range(1, this.list.pages + 1);
    }

    onClick (page: number) {
        if (page > 0 && page <= this.list.pages) {
            this.change.emit(page);
        }
        return false;
    }

    href (page: number) {
        return `${this.list.uri}?${_.map(_.assign(this._params.params, { page: page }), (value, param) => `${param}=${value}`).join('&')}`;
    }

    first (page) {
        return page == 1 ? 1 : null;
    }

    last(page) {
        return page == this.list.pages ? this.list.pages : null;
    }
}

Pagination Template (index.html) - I use bootstrap for styling

<div>
        <ul class="pagination">
            <li [class.disabled]="first(list.page)"><a (click)="onClick(list.page - 1)" [attr.href]="href(list.page - 1)">&laquo;</a></li>

            <template ngFor let-page [ngForOf]="pages">
                <li *ngIf="(page >= list.page - 2 && page <= list.page + 2) || first(page) || last(page)" [ngSwitch]="(page != list.page - 2 && page != list.page + 2) || first(page) || last(page)" [class.active]="page == list.page">
                    <a *ngSwitchWhen="true" (click)="onClick(page)" [attr.href]="href(page)">{{page}}</a>
                    <a *ngSwitchDefault (click)="onClick(page)" [attr.href]="href(page)">...</a>
                </li>
            </template>

            <li [class.disabled]="last(list.page)"><a (click)="onClick(list.page + 1)" [attr.href]="href(list.page + 1)">&raquo;</a></li>
        </ul>
    </div>

Usage in article list template:

...
<pagination *ngIf="list.pages > 1" [(list)]="list" (change)="page($event)" class="text-center"></pagination>
...

The article service in my little project requests a range of articles from the server using the Range header.

Hope you find this helpful!

Upvotes: 0

Vlado Tesanovic
Vlado Tesanovic

Reputation: 6424

Why you simply don't do this:

<a [routerLink]="['./Cmp', {limit: 10, offset: 10}]">Previous Page</a>
<a [routerLink]="['./Cmp', {limit: 10, offset: 20}]">Next Page</a>

Upvotes: 0

Related Questions