Подтвердить что ты не робот

Измените один параметр маршрута на текущем маршруте в Angular 2

Можно ли изменить один параметр маршрута в текущем маршруте, сохраняя все остальные параметры? Это предназначено для использования в пейджинговом компоненте, который будет перенаправляться на новую страницу, сохраняя при этом другие части текущего маршрута.

Некоторые примеры:

  • Страница по умолчанию на стр. 2: orders?foo=foo&bar=bar > orders?foo=foo&bar=bar&page=2
  • Страница по умолчанию на страницу 2 (дочерняя): orders/;foo=foo;bar=bar > orders/;foo=foo;bar=bar;page=2
  • Страница 2 - 3 на дочернем и родительском с параметрами: orders/;foo=foo;page=2?bar=bar > orders/;foo=foo;page=3?bar=bar

Я попытался использовать routerLink, однако это теряет любые дополнительные параметры, которые не являются первоначально частью ссылки маршрутизатора.

Я также попытался использовать текущий Router для получения Instruction для текущего пути, однако изменение параметров Instruction, похоже, не имеет никакого эффекта при вызове navigateByInstruction().

4b9b3361

Ответ 1

Почему вы просто этого не делаете:

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

Ответ 2

Это довольно легко. Скажем, у нас есть метод в нашем ListComponent, который изменяет страницу и сохраняет все остальные параметры без изменений (например, параметры поиска - не может изменить страницу и забыть, что мы что-то искали:):

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
}

Я использовал Underscore, чтобы назначить параметр страницы существующей карте параметров из моего личного, вложенного объекта RouteParams. Эта карта обновляется при навигации, поэтому мы все хорошо, просто помните, что вы не можете напрямую ее изменить, это можно вывести.

Вот моя реализация списка статей вместе с компонентом разбиения на страницы, используемым в качестве директивы для предоставления разбивки на страницы:

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

Шаблон разбиения на страницы (index.html) - Я использую бутстрап для стилизации

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

Использование в шаблоне списка статей:

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

Служба статьи в моем маленьком проекте запрашивает ряд статей с сервера с использованием заголовка Range.

Надеюсь, вы найдете это полезным!

Ответ 3

вы можете использовать параметр параметра запроса вместо параметра, который он использует, например

при вызове компонента

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

в вызываемой компоненте

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

Ответ 4

Мне было бы неплохо, если activeRoute мог бы вернуть простой клон текущего маршрута [], который должен быть обработан до вызова router.navigate(nextroutearray), но я не нашел такого метода в api.

Поэтому я централизовал требование в простую службу, где я могу проанализировать текущий activeRoute + набор параметров, которые будут использоваться для следующего маршрута. Я не думаю, что этот код будет охватывать всю сложность URL-адреса в маршруте, но в моем случае я использую только параметры на последней части маршрута, поэтому он работает для меня:

Метод службы выглядит следующим образом:

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

Затем я могу использовать этот метод в любом компоненте, который получает мой файл Sitemap:

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

И в html ссылка на метод setNextTab выглядит следующим образом:

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