web-dev-qa-db-fra.com

Modifiez un paramètre de route unique sur la route actuelle dans Angular 2

Est-il possible de modifier un seul paramètre d'itinéraire dans l'itinéraire actuel, tout en conservant tous les autres paramètres? Ceci est destiné à être utilisé dans un composant de pagination, qui sera acheminé vers une nouvelle page tout en conservant les autres parties de l'itinéraire actuel.

Quelques exemples:

  • Page par défaut à la page 2: orders?foo=foo&bar=bar> orders?foo=foo&bar=bar&page=2
  • Page par défaut à la page 2 (enfant): orders/;foo=foo;bar=bar> orders/;foo=foo;bar=bar;page=2
  • Pages 2 à 3 sur l'enfant et le parent avec paramètres: orders/;foo=foo;page=2?bar=bar> orders/;foo=foo;page=3?bar=bar

J'ai essayé d'utiliser un routerLink, mais cela perd tout paramètre supplémentaire qui ne fait pas partie à l'origine de la liaison du routeur.

J'ai également essayé d'utiliser le Router actuel pour obtenir un Instruction pour le chemin actuel, mais la modification des paramètres du Instruction ne semble pas avoir d'effet lors de l'appel de navigateByInstruction().

26
Robert Davey

vous pouvez utiliser l'option de paramètre de requête au lieu du paramètre utilisé comme

dans le composant appelant

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

dans le composant appelé

  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));
2
Sunil Kumar

Je serais bien si activeRoute pouvait retourner un simple clone de la route actuelle [] à manipuler avant d'appeler à router.navigate (nextroutearray), mais je n'ai pas trouvé une telle méthode dans l'API.

J'ai donc centralisé l'exigence dans un service simple, où je peux analyser l'actuel Route actif, + un ensemble de paramètres à utiliser pour la route suivante. Je ne pense pas que ce code couvrira toute la complexité de l'url d'un itinéraire, mais dans mon cas, je n'utilise que des paramètres sur la dernière partie de l'itinéraire, donc cela fonctionne pour moi:

La méthode de service ressemble à ceci:

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

Ensuite, je peux utiliser cette méthode dans n'importe quel composant obtenant mon service sitemap injecté:

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

Et dans le html, le lien vers la méthode setNextTab ressemble à ceci:

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

2
Kjeld Poulsen

Pourquoi vous ne faites tout simplement pas cela:

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

C'est assez simple. Disons que nous avons une méthode dans notre ListComponent qui change la page et garde tous les autres paramètres intacts (comme les paramètres liés à la recherche - ne peut pas changer la page et oublier que nous cherchions quelque chose :):

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
}

J'ai utilisé Underscore pour attribuer un paramètre de page à la carte existante des paramètres de mon objet RouteParams injecté privé. Cette carte est mise à jour lors de la navigation, nous sommes donc tous bons, n'oubliez pas que vous ne pouvez pas la modifier directement, elle est imitable.

Voici mon implémentation d'une liste d'articles avec un composant de pagination utilisé comme directive pour fournir la 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;
    }
}

Modèle de pagination (index.html) - J'utilise bootstrap pour le style

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

Utilisation dans le modèle de liste d'articles:

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

Le service d'article de mon petit projet demande une gamme d'articles au serveur en utilisant l'en-tête Range.

J'espère que ceci vous aidera!

0
Kesarion