Tham số tuyến đường tùy chọn 2 góc


180

Có thể có một tham số tuyến tùy chọn trong tuyến Angular 2 không? Tôi đã thử cú pháp Angular 1.x trong RouteConfig nhưng nhận được lỗi dưới đây:

"NGOẠI TRỪ GỐC: Đường dẫn" / user /: id? "Chứa"? "Không được phép trong cấu hình tuyến đường."

@RouteConfig([
{
    path: '/user/:id?',
    component: User,
    as: 'User'
}])

Câu trả lời:


298

Bạn có thể xác định nhiều tuyến có và không có tham số:

@RouteConfig([
    { path: '/user/:id', component: User, name: 'User' },
    { path: '/user', component: User, name: 'Usernew' }
])

và xử lý tham số tùy chọn trong thành phần của bạn:

constructor(params: RouteParams) {
    var paramId = params.get("id");

    if (paramId) {
        ...
    }
}

Xem thêm vấn đề về github có liên quan: https://github.com/angular/angular/issues35325


11
Sửa lỗi cho tôi nếu tôi sai, nhưng giải pháp này chỉ hiệu quả với tôi khi thứ tự các tuyến trong mảng bị đảo ngược, tức là tuyến có tham số xảy ra trước một tuyến khác. Cho đến khi tôi làm điều đó, bộ định tuyến chỉ khớp với tuyến mà không có tham số.
Aviad P.

10
giải pháp này vẫn còn áp dụng? Tôi nhận thấy việc chuyển từ "Người dùng" sang "Người dùng mới" sẽ khởi tạo lại thành phần 'Người dùng'
teleaziz

19
cũ nhưng một vấn đề lớn với cách tiếp cận này là mỗi tuyến được coi là tuyến duy nhất và nó làm cho việc tái sử dụng thành phần là không thể.
Agony

4
Theo ghi nhận của @teleaziz, việc nối thêm tham số sẽ kết xuất lại thành phần. Để tránh điều này, Martin Cremer trả lời; thêm gốc 'redirectTo' với giá trị tham số trống, rất hiệu quả đối với tôi: stackoverflow.com/a/49159166/1364650 - nhưng điều đó khá khó khăn, tôi nghĩ rằng họ chỉ nên hỗ trợ các tham số tuyến tùy chọn đúng cách.
Vincent Sels

2
Đối với những người đang tự hỏi tại sao RouteParamskhông nhập vào thành phần, hãy kiểm tra điều này: stackoverflow.com/a/36792261/806202 . Giải pháp là sử dụng ActivatedRoute:route.snapshot.params['routeParam']
Arsen Khachaturyan

89
{path: 'users', redirectTo: 'users/', pathMatch: 'full'},
{path: 'users/:userId', component: UserComponent}

Bằng cách này, thành phần không được kết xuất lại khi tham số được thêm vào.


6
Câu trả lời này là tốt nhất. Nó không kết xuất lại cùng một thành phần và nó không yêu cầu nhiều thành phần.
Rex

4
Câu trả lời hay nhất, nhưng tôi đã thêm vào pathMatch: 'full'để chuyển hướng, nếu không thì các đường dẫn như users/admincũng được chuyển hướng trong trường hợp của tôi
Valeriy Katkov

4
Câu trả lời này chỉ tốt nhất nếu bạn ổn với dấu gạch chéo trên các URL của bạn như được xem trong trình duyệt. Ví dụ , có thể xem xét một giá trị đại diện cho id một id không xác định ', /users/allhoặc /users/homeđọc' tất cả 'hoặc' nhà 'là idvà chỉ cần bỏ qua nó nếu nó phù hợp với giá trị ma thuật của bạn. Sau đó, dòng đầu tiên ở trên trở thành redirectTo: 'users/home'hoặc bất cứ điều gì bạn quyết định. Đối với tôi một dấu gạch chéo thực sự nổi bật như một cái gì đó sai.
Simon_Weaver

@Simon_Weaver Tôi đồng ý. Tôi đã tìm thấy một giải pháp khác bằng cách sử dụng một công cụ đối sánh không có vấn đề này: stackoverflow.com/a/56391974/664533
Wayne Maurer

1
đó là một câu thần chú đơn giản nhưng khá khó phá vỡ: D Giải pháp tốt nhất!
Verri

45

Bạn nên sử dụng tham số truy vấn khi thông tin là tùy chọn.

Thông số tuyến hoặc tham số truy vấn?

Không có luật chuyên chế. Nói chung,

thích tham số tuyến khi

  • giá trị được yêu cầu.
  • giá trị là cần thiết để phân biệt một tuyến đường này với một tuyến đường khác.

thích tham số truy vấn khi

  • giá trị là tùy chọn.
  • giá trị là phức tạp và / hoặc đa biến.

từ https://angular.io/guide/router#optional-route-parameter

Bạn chỉ cần lấy tham số từ đường dẫn.

@RouteConfig([
{
    path: '/user/',
    component: User,
    as: 'User'
}])

6
Thay đổi thành phần tùy chọn tham số tuyến đường tùy chọn, nhưng thay đổi queryParams thì không. Ngoài ra nếu bạn giải quyết một số dữ liệu trước khi điều hướng tuyến, nó sẽ được yêu cầu mỗi khi bạn thay đổi thông số tuyến tùy chọn.
Rakhat

1
FYI, liên kết neo đó không hoạt động nữa. Liên kết mới dường như là Thông số Tuyến đường: Bắt buộc hoặc tùy chọn?
spốmmahn

20

Angular 4 - Giải pháp để giải quyết thứ tự của tham số tùy chọn:

LÀM CÁI NÀY:

const appRoutes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'products', component: ProductsComponent},
  {path: 'products/:id', component: ProductsComponent}
]

Lưu ý rằng productsproducts/:idcác tuyến đường được đặt tên chính xác như nhau. Angular 4 sẽ theo đúng productscác tuyến đường không có tham số và nếu tham số thì nó sẽ đi theo products/:id.

Tuy nhiên, con đường cho con đường phi tham số productsphải không có một gạch chéo, nếu góc sẽ không đúng cách đối xử với nó như một tham số-path. Vì vậy, trong trường hợp của tôi, tôi đã có dấu gạch chéo cho các sản phẩm và nó không hoạt động.

ĐỪNG LÀM ĐIỀU NÀY:

...
{path: 'products/', component: ProductsComponent},
{path: 'products/:id', component: ProductsComponent},
...

Nếu cả hai đang đi đến ProductsComponent, làm thế nào để bạn đối phó với tham số tùy chọn ở đó?
Arwin

1
Bạn có thể truy cập các tham số: id1 ,: id2, v.v. cũng như url được yêu cầu trong ProductsComponent như vậy: this.route.url.first () .mergeMap ((url) => {// console.log ('1: thay đổi url được phát hiện '+ url); return this.route.params.do ((params) => {// console.log (' 2: url + params thay đổi được phát hiện '+ params ["id1"] +' '+ params ["id2"]); this.id1 = params ["id1"]; this.id2 = params ["id2"];})})
ObjectiveTC

2
Hãy nhớ rằng bạn cũng có thể chuyển datađến thành phần, có thể khác nhau cho từng tuyến ngay cả với cùng một thành phần. Ví dụ {path: 'products', component: ProductsComponent, data: { showAllProducts: true} },có thể được sử dụng và sau đó bạn kiểm tra showAllProducts. Đẹp hơn một chút sau đó kiểm tra null, nhưng đối với các trường hợp đơn giản hơn có lẽ là tốt.
Simon_Weaver

1
Thật không may, giải pháp này sẽ ngăn Angular sử dụng lại thành phần giữa sản phẩm và sản phẩm /: id. Các thành phần sẽ được tái lập.
Kodiak

@Kodiak - Tôi không tin đó là chính xác. Sự hiểu biết của tôi là trong app.module.ts, ProductsComponent được khởi tạo một lần và động cơ góc sau đó sử dụng lại Sản phẩm được tạo tức thời đó theo từng sự kiện có thể điều hướng (sản phẩm và sản phẩm /: id, v.v.). Bạn có thể giải thích hoặc chứng minh làm thế nào ProductsComponent có thể được khởi tạo lại trong mã ở trên không và làm thế nào bạn có thể ngăn chặn việc khởi tạo lại?
ObjectiveTC

11

Câu trả lời của rerezz là khá hay nhưng nó có một lỗ hổng nghiêm trọng. Nó gây ra Userthành phần để chạy lại ngOnInitphương thức.

Nó có thể có vấn đề khi bạn làm một số thứ nặng ở đó và không muốn nó được chạy lại khi bạn chuyển từ tuyến không tham số sang tuyến tham số. Mặc dù hai tuyến này có nghĩa là bắt chước một tham số url tùy chọn, không trở thành 2 tuyến riêng biệt.

Đây là những gì tôi đề nghị để giải quyết vấn đề:

const routes = [
  {
    path: '/user',
    component: User,
    children: [
      { path: ':id', component: UserWithParam, name: 'Usernew' }
    ]
  }
];

Sau đó, bạn có thể di chuyển logic chịu trách nhiệm xử lý param cho UserWithParamthành phần và để lại logic cơ sở trong Userthành phần. Bất cứ điều gì bạn làm trong User::ngOnInitsẽ không được chạy lại khi bạn điều hướng từ / user đến / user / 123 .

Đừng quên đặt <router-outlet></router-outlet>trong Usermẫu của.


Tránh các thành phần được tái tạo là một điều tốt nếu hiệu suất là quan trọng. Tôi có một giải pháp khác cũng tránh việc tránh thành phần được tạo lại: stackoverflow.com/a/56391974/664533
Wayne Maurer

4

Các câu trả lời được đề xuất ở đây, bao gồm câu trả lời được chấp nhận từ rerezz , đề xuất thêm nhiều mục tuyến hoạt động tốt.

Tuy nhiên, thành phần sẽ được tạo lại khi thay đổi giữa các mục tuyến, tức là giữa mục nhập tuyến với tham số và mục không có tham số.

Nếu bạn muốn tránh điều này, bạn có thể tạo trình so khớp tuyến đường của riêng bạn sẽ khớp với cả hai tuyến đường:

export function userPageMatcher(segments: UrlSegment[]): UrlMatchResult {
    if (segments.length > 0 && segments[0].path === 'user') {
        if (segments.length === 1) {
            return {
                consumed: segments,
                posParams: {},
            };
        }
        if (segments.length === 2) {
            return {
                consumed: segments,
                posParams: { id: segments[1] },
            };
        }
        return <UrlMatchResult>(null as any);
    }
    return <UrlMatchResult>(null as any);
 }

Sau đó sử dụng công cụ đối sánh trong cấu hình tuyến đường của bạn:

const routes: Routes = [
    {
        matcher: userPageMatcher,
        component: User,
    }
];

@KevinBeal Tôi đã triển khai khá nhiều công cụ đối sánh hoạt động với AOT. Lỗi gì bạn đang nhận được ở đây?
Wayne Maurer

Giáo sư. Đó là cái gì đó khác. Matcher của tôi hoạt động với AOT.
Kevin Beal

đây là một chút khó khăn nhưng giải pháp tốt nhất cho vấn đề này
fedor.belov

4

Với angular4 chúng ta chỉ cần tổ chức các tuyến cùng nhau theo thứ bậc

const appRoutes: Routes = [
  { 
    path: '', 
    component: MainPageComponent 
  },
  { 
    path: 'car/details', 
    component: CarDetailsComponent 
  },
  { 
    path: 'car/details/platforms-products', 
    component: CarProductsComponent 
  },
  { 
    path: 'car/details/:id', 
    component: CadDetailsComponent 
  },
  { 
    path: 'car/details/:id/platforms-products', 
    component: CarProductsComponent 
  }
];

Điều này làm việc cho tôi. Bằng cách này, bộ định tuyến biết tuyến đường tiếp theo dựa trên các tham số id tùy chọn là gì.


1

Chạy vào một ví dụ khác của vấn đề này, và trong khi tìm kiếm một giải pháp cho nó đã đến đây. Vấn đề của tôi là tôi đang làm những đứa trẻ, và lười tải các thành phần cũng để tối ưu hóa mọi thứ một chút. Tóm lại nếu bạn lười tải mô-đun cha. Điều chính là tôi sử dụng '/: id' trong tuyến đường và nó phàn nàn về '/' là một phần của nó. Không phải vấn đề chính xác ở đây, nhưng nó được áp dụng.

Định tuyến ứng dụng từ cha mẹ

...
const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: 'pathOne',
        loadChildren: 'app/views/$MODULE_PATH.module#PathOneModule'
      },
      {
        path: 'pathTwo',
        loadChildren: 'app/views/$MODULE_PATH.module#PathTwoModule'
      },
...

Con đường lười tải

...
const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: '',
        component: OverviewComponent
      },
      {
        path: ':id',
        component: DetailedComponent
      },
    ]
  }
];
...


0

Đối mặt với một vấn đề tương tự với tải lười biếng, tôi đã làm điều này:

const routes: Routes = [
  {
    path: 'users',
    redirectTo: 'users/',
    pathMatch: 'full'
  },
  {
    path: 'users',
    loadChildren: './users/users.module#UserssModule',
    runGuardsAndResolvers: 'always'
  },
[...]

Và sau đó trong thành phần:

  ngOnInit() {
    this.activatedRoute.paramMap.pipe(
      switchMap(
        (params: ParamMap) => {
          let id: string = params.get('id');
          if (id == "") {
            return of(undefined);
          }
          return this.usersService.getUser(Number(params.get('id')));
        }
      )
    ).subscribe(user => this.selectedUser = user);
  }

Cách này:

  • Các tuyến đường mà không /được chuyển hướng đến các tuyến đường với. Bởi vì pathMatch: 'full', chỉ có tuyến đường đầy đủ cụ thể như vậy được chuyển hướng.

  • Sau đó, users/:idđược nhận. Nếu con đường thực tế là users/, id"", vì vậy kiểm tra xem nó trong ngOnInitvà hành động phù hợp; khác, idlà id và tiến hành.

  • Phần còn lại của các thành phần hoạt động trên selectedUserhoặc không được xác định (* ngNếu và những thứ tương tự).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.