Làm cách nào để có được thông số truy vấn từ url trong Angular 2?


236

Tôi sử dụng angular2.0.0-beta.7. Khi một thành phần được tải trên một đường dẫn như /path?query=value1nó được chuyển hướng đến /path. Tại sao các thông số GET bị xóa? Làm thế nào tôi có thể bảo tồn các tham số?

Tôi có một lỗi trong các bộ định tuyến. Nếu tôi có một tuyến đường chính như

@RouteConfig([
  {
      path: '/todos/...',
      name: 'TodoMain',
      component: TodoMainComponent
  }
])

và con đường của tôi như

@RouteConfig([
  { path: '/', component: TodoListComponent, name: 'TodoList', useAsDefault:true },
  { path: '/:id', component: TodoDetailComponent, name:'TodoDetail' }
])

sau đó tôi không thể nhận được thông số trong TodoListComponent. Tôi có thể lấy

params("/my/path;param1=value1;param2=value2") 

nhưng tôi muốn cổ điển

query params("/my/path?param1=value1&param2=value2")

1
Làm thế nào bạn chỉ định @RouteConfigcho điều này path?
Pankaj Parkar

Tôi tìm thấy lỗi. Tôi có tuyến chính và tuyến con và nếu tôi có tuyến chính như {path: '/ todos / ...', tên: 'TodoMain', thành phần: TodoMainComponent} và tuyến con {path: '/', thành phần: TodoListComponent, tên: 'TodoList', useAsDefault: true}, nó không hoạt động và chuyển hướng đến url mà không có thông số truy vấn.
FireGM

Câu trả lời:


411

Bằng cách tiêm một thể hiện của ActivatedRoutemột người có thể đăng ký vào một loạt các vật quan sát, bao gồm cả a queryParamsparamscó thể quan sát được:

import {Router, ActivatedRoute, Params} from '@angular/router';
import {OnInit, Component} from '@angular/core';

@Component({...})
export class MyComponent implements OnInit {

  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    // Note: Below 'queryParams' can be replaced with 'params' depending on your requirements
    this.activatedRoute.queryParams.subscribe(params => {
        const userId = params['userId'];
        console.log(userId);
      });
  }

}

MỘT LƯU Ý KHAI THÁC KHÔNG GIỚI HẠN

@Reto và @ codef0rmer đã chỉ ra khá đúng rằng, theo các tài liệu chính thức, một phương thức unsubscribe()thành phần bên trong onDestroy()là không cần thiết trong trường hợp này. Điều này đã được loại bỏ khỏi mẫu mã của tôi. (xem hộp cảnh báo màu xanh trong hướng dẫn này )


2
Tôi cũng đề nghị thay thế thuê bao bằng một lời hứa - trong trường hợp đặc biệt này. this .activatedRoute.params.toPromise () .then (hồi đáp => ...) .catch (error => ...);
tháng

Tôi có thể vượt qua "activRoute" ở đâu?
michali

19
Từ tài liệu chính thức: Tôi có cần hủy đăng ký không? The Router manages the observables it provides and localizes the subscriptions. The subscriptions are cleaned up when the component is destroyed, protecting against memory leaks, so we don't need to unsubscribe from the route params Observable.
Reto

chuyển hướng góc mà không bắn thuê bao (hoặc lời hứa). Tôi có thể thấy cuộc gọi lại oAUth ban đầu với mã thông báo, nhưng sau đó nó chuyển hướng đến tuyến đường mà không có tham số truy vấn và console.log (param) chỉ là một đối tượng trống.
FlavorScape

1
@Sobhan, vâng, có một sự khác biệt. Toán tử switchMap trả về một Observable trong khi toán tử đăng ký cho phép người quan sát (thành phần của chúng ta) thấy các mục cuối cùng được phát ra bởi một Observable. Vì vậy, trong các tài liệu có 2 trường hợp của sơ đồ chuyển mạch đang được sử dụng. 1) Họ đã sử dụng switchMap để nối thêm yêu cầu cho các anh hùng. SwitchMap, không giống như đăng ký, sẽ đảm bảo rằng yêu cầu bị hủy nếu người dùng điều hướng lại tuyến đường trong khi vẫn lấy được một anh hùng. 2) Một ống không đồng bộ được sử dụng. Các ống async tiêu thụ một thứ có thể quan sát được, vì vậy người ta không được đăng ký (Ống async sẽ làm điều đó cho bạn).
Stephen Paul

103

Khi một URL như thế này http://stackoverflow.com?param1=value

Bạn có thể lấy param1 bằng mã theo sau:

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';

@Component({
    selector: '',
    templateUrl: './abc.html',
    styleUrls: ['./abc.less']
})
export class AbcComponent implements OnInit {
    constructor(private route: ActivatedRoute) { }

    ngOnInit() {
        // get param
        let param1 = this.route.snapshot.queryParams["param1"];
    }
}

2
điều này có nghĩa là bạn không cần thêm "/: id" trong đường dẫn Routeconfig nữa? bởi vì tôi nhận được "không xác định" khi tôi sử dụng điều này nên tôi vẫn phải gặp lỗi ở đâu đó
Axelle

2
Tuyệt quá. Điều này tôi đang tìm kiếm bởi vì tôi cần đọc các thông số trực tiếp từ một url máy chủ động. Tôi không thể sử dụng điều hướng.
The.Bear

37

Mặc dù câu hỏi chỉ định phiên bản beta 7 , câu hỏi này cũng xuất hiện dưới dạng kết quả tìm kiếm hàng đầu trên Google cho các cụm từ phổ biến như tham số truy vấn 2 góc . Vì lý do đó, đây là câu trả lời cho bộ định tuyến mới nhất (hiện đang ở giai đoạn alpha.7 ).

Cách các thông số được đọc đã thay đổi đáng kể. Trước tiên, bạn cần thêm phụ thuộc được gọi Routertrong các tham số hàm tạo của bạn như:

constructor(private router: Router) { }

và sau đó chúng ta có thể đăng ký các tham số truy vấn trên ngOnInitphương thức của mình (hàm tạo cũng không sao, nhưng ngOnInitnên được sử dụng để kiểm tra) như

this.router
  .routerState
  .queryParams
  .subscribe(params => {
    this.selectedId = +params['id'];
  });

Trong ví dụ này, chúng tôi đọc id param truy vấn từ URL như example.com?id=41.

Vẫn còn vài điều cần chú ý:

  1. Truy cập thuộc tính paramslike params['id']luôn trả về một chuỗi và điều này có thể được chuyển đổi thành số bằng cách thêm tiền tố vào +.
  2. Lý do tại sao các tham số truy vấn được tìm nạp với có thể quan sát được là vì nó cho phép sử dụng lại cùng một thể hiện thành phần thay vì tải một tham số mới. Mỗi lần param param truy vấn được thay đổi, nó sẽ gây ra một sự kiện mới mà chúng tôi đã đăng ký và do đó chúng tôi có thể phản ứng với những thay đổi tương ứng.

Có cách nào để có nhiều tham số đến cùng một thành viên không? Ví dụ: tôi muốn 'id' hoặc 'nhận dạng' đi tới this.selectedId.
phandinhlan

@phandinhlan: Chà, đó thực sự không phải là một câu hỏi liên quan đến Angular 2. Tất nhiên nó có thể được thực hiện, nhưng bạn cần phải tự xác định logic. Về cơ bản những gì bạn muốn làm là trước tiên kiểm tra xem khóa đầu tiên được xác định và chỉ sau đó đọc giá trị từ nó, và nếu không, hãy đọc giá trị bằng một khóa khác. Điều này có thể đạt được với một cái gì đó như if (params.hasOwnProperty('id')) { this.selectedId = params['id'] } else { this.selectedId = params['identification']}.
Roope Hakulinen

Phải, cuối cùng tôi đã làm một cái gì đó như thế. Tôi chỉ nghĩ rằng sẽ có một số cách "được xây dựng" như: this.selectedId = + params ['id']; this.selectedId = + params ['nhận dạng']; Tất nhiên điều đó không có ý nghĩa gì và không hoạt động.
phandinhlan

28

Tôi thực sự thích câu trả lời của @ StevePaul nhưng chúng tôi có thể làm tương tự mà không cần đăng ký / hủy đăng ký cuộc gọi bên ngoài.

import { ActivatedRoute } from '@angular/router';
constructor(private activatedRoute: ActivatedRoute) {
    let params: any = this.activatedRoute.snapshot.params;
    console.log(params.id);
    // or shortcut Type Casting
    // (<any> this.activatedRoute.snapshot.params).id
}

7
Tất nhiên, điều đáng lưu ý với điều này là nó sẽ là giá trị ban đầu và những thay đổi tiếp theo sẽ không được phản ánh. Vì vậy, nếu bạn thay đổi các tham số URL theo chương trình như một phần logic của bạn, đó là điều bạn cần phải biết
thuận

Không chắc điều này có thay đổi với các phiên bản sau của Angular hay không, nhưng bây giờ tôi thấy nó trong this.activatedRoute.snapshot.queryParams
Michael

21

Để gửi thông số truy vấn

import { Router } from '@angular/router';
this.router.navigate([ '/your-route' ], { queryParams: { key: va1, keyN: valN } });

Để nhận thông số truy vấn

import { ActivatedRoute } from '@angular/router';
this.activatedRoute.queryParams.subscribe(params => {
    let value_1 = params['key'];
    let value_N = params['keyN'];
});

Nguồn chính thức


Việc đọc hoạt động tốt. Nhưng nó là trường hợp nhạy cảm. Làm thế nào chúng ta có thể làm cho nó không nhạy cảm?
Unnie

12

Xin chào, bạn có thể sử dụng URLSearchParams, bạn có thể đọc thêm về nó ở đây .

nhập khẩu:

import {URLSearchParams} from "@angular/http";

và chức năng:

getParam(){
  let params = new URLSearchParams(window.location.search);
  let someParam = params.get('someParam');
  return someParam;
}

Lưu ý : Nó không được hỗ trợ bởi tất cả các nền tảng và dường như ở trạng thái "TRẢI NGHIỆM" bởi các tài liệu góc cạnh


2
Điều này không làm việc cho tôi. Tôi đã thấy rằng window.location.search bao gồm dấu hỏi hàng đầu của các tham số chuỗi truy vấn. Vì vậy, khóa cho tham số đầu tiên sẽ có dấu chấm hỏi được đặt trước.
AJ Morris

AJ Morris, để giải quyết vấn đề của bạn: if (window.location.search.indexOf('?') == 0){ normalizedQueryString = window.location.search.substring(1); } else { normalizedQueryString = window.location.search; } let params = new URLSearchParams(normalizedQueryString);
ambidexterous

URLSearchParams không dùng nữa. Bây giờ bạn có thể làm điều đó với ActivatedRoute.
Robert Blasco Villarroya

7

Trước hết, những gì tôi đã tìm thấy khi làm việc với Angular2 là url có chuỗi truy vấn sẽ là /path;query=value1

Để truy cập nó trong một thành phần bạn sử dụng Đây là, nhưng bây giờ theo một khối mã:

    constructor(params: RouteParams){
    var val = params.get("query");
    }

Về lý do tại sao nó sẽ bị xóa khi bạn tải thành phần, đó không phải là hành vi mặc định. Tôi đã kiểm tra cụ thể trong một dự án thử nghiệm sạch và không được chuyển hướng hoặc thay đổi. Đây có phải là một tuyến đường mặc định hoặc một cái gì đó đặc biệt về định tuyến?

Đọc về định tuyến với các chuỗi truy vấn và thông số trong Hướng dẫn Angular2 tại https://angular.io/docs/ts/latest/guide/router.html#!#query-parameter


Tôi không thể sử dụng các thông số như "; param1 = value1; param2 = value2", liên kết này được tạo trên một trang web khác và chuyển hướng trên trang web của tôi như "example.com/auth?code_for_auth=askjfbkajdsbfksajdf"
FireGM

Hiện tại cách thức định tuyến được thiết lập trong Angular2, tôi không nghĩ nó thực sự có thể. Một số cách giải quyết sẽ là cần thiết vì định tuyến con không phụ thuộc vào url ma trận. Như tôi biết ít nhất. Tôi sẽ chặn nó tại máy chủ web của mình và biến chúng thành một bản hack, hút nhưng tôi không thể nghĩ ra một cách khác vào lúc này
Namirna

Bạn không có khả năng yêu cầu trang web liên kết thay đổi url của họ?
Namirna

1
Không. Nhưng tôi đã giải quyết vấn đề đơn giản bằng cách phân tích thủ công Location.path ()
FireGM

4
Giải pháp này không dùng nữa!

7

Bạn có thể nhận được các tham số truy vấn khi được truyền vào URL bằng ActivatedRoute như được nêu dưới đây: -

url: - http: /domain.com? test = abc

import { Component } from '@angular/core';
import { ActivatedRoute }     from '@angular/router';

@Component({
  selector: 'my-home'
})
export class HomeComponent {

  constructor(private sharedServices : SharedService,private route: ActivatedRoute) { 
    route.queryParams.subscribe(
      data => console.log('queryParams', data['test']));
  }

}

7

Nhận thông số URL làm đối tượng.

import { Router } from '@angular/router';
constructor(private router: Router) {
    console.log(router.parseUrl(router.url));
}

2

Nếu bạn chỉ muốn nhận được tham số truy vấn một lần, cách tốt nhất là sử dụng mất phương pháp, do đó bạn không cần phải lo lắng về việc hủy đăng ký. Đây là đoạn trích đơn giản: -

constructor(private route: ActivatedRoute) {
  route.snapshot.queryParamMap.take(1).subscribe(params => {
     let category = params.get('category')
     console.log(category);
  })
}

Lưu ý: Xóa lấy (1) nếu bạn muốn sử dụng các giá trị tham số trong tương lai.


2

bây giờ thì đúng là vậy:

this.activatedRoute.queryParams.subscribe((params: Params) => {
  console.log(params);
});

1
Cảm ơn bạn vì đoạn mã này, có thể cung cấp một số trợ giúp ngắn hạn. Một lời giải thích phù hợp sẽ cải thiện đáng kể giá trị lâu dài của nó bằng cách chỉ ra lý do tại sao đây là một giải pháp tốt cho vấn đề và sẽ giúp nó hữu ích hơn cho những người đọc tương lai với những câu hỏi tương tự khác. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số lời giải thích, bao gồm các giả định bạn đã thực hiện
Shawn C.

1

Tôi hy vọng nó sẽ giúp người khác.

Câu hỏi ở trên nói rằng giá trị param truy vấn là cần thiết sau khi trang đã được chuyển hướng và chúng tôi có thể giả định rằng giá trị ảnh chụp nhanh (thay thế không thể quan sát) là đủ.

Không ai ở đây đề cập đến snapshot.paramMap.get từ tài liệu chính thức .

this.route.snapshot.paramMap.get('id')

Vì vậy, trước khi gửi, hãy thêm phần này vào thành phần gửi / chuyển hướng:

import { Router } from '@angular/router';

sau đó chuyển hướng lại thành một trong hai (tài liệu ở đây ):

this.router.navigate(['/heroes', { id: heroId, foo: 'foo' }]);

hoặc đơn giản:

this.router.navigate(['/heroes', heroId ]);

Hãy chắc chắn rằng bạn đã thêm phần này vào mô-đun định tuyến của mình như được ghi lại ở đây :

 { path: 'hero/:id', component: HeroDetailComponent }

Và cuối cùng, trong thành phần của bạn cần sử dụng tham số truy vấn

  • thêm nhập khẩu (tài liệu ở đây ):

    import { Router, ActivatedRoute, ParamMap } from '@angular/router';
  • tiêm ActivatedRoute

(tài liệu cũng nhập switchMap và cũng tiêm Router và HeroService - nhưng chúng chỉ cần cho thay thế có thể quan sát được - chúng KHÔNG cần thiết khi bạn sử dụng thay thế ảnh chụp nhanh như trong trường hợp của chúng tôi):

    constructor(
      private route: ActivatedRoute
    ) {}
  • và nhận giá trị bạn cần (tài liệu ở đây ):

    ngOnInit() {
      const id = this.route.snapshot.paramMap.get('id');
    }

LƯU Ý: NẾU BẠN THÊM ROUTING-MODULE ĐẾN MỘT MODU ĐẶC ĐIỂM (NHƯ ĐƯỢC HIỂN THỊ TRONG TÀI LIỆU) HÃY ĐẢM BẢO R APPNG TRONG APP.MODULE.ts R MODNG MODULE ROUTING TRƯỚC KHI AppRoutingModule (hoặc tệp khác với các ứng dụng gốc). CÁC ĐƯỜNG TÍNH NĂNG KHÁC SILL KHÔNG ĐƯỢC TÌM KIẾM (NHƯ VẬY NÊN KẾT THÚC SAU {path: '**', redirectTo: '/ not-find'} và bạn sẽ chỉ thấy tin nhắn không tìm thấy).


1

Bạn chỉ cần tiêm ActivatedRoute trong hàm tạo và sau đó chỉ cần truy cập params hoặc queryParams qua nó

constructor(private route:ActivatedRoute){}
ngOnInit(){
        this.route.queryParams.subscribe(params=>{
        let username=params['username'];
      });
 }

Trong một số trường hợp, nó không cung cấp bất cứ điều gì trong NgOnInit ... có thể do cuộc gọi init trước khi khởi tạo params trong trường hợp này, bạn có thể đạt được điều này bằng cách yêu cầu quan sát chờ một thời gian bằng chức năng debounceTime (1000)

ví dụ =>

 constructor(private route:ActivatedRoute){}
    ngOnInit(){
            this.route.queryParams.debounceTime(100).subscribe(params=>{
            let username=params['username'];
          });
     }

debounceTime () Phát ra một giá trị từ nguồn chỉ có thể quan sát được sau khi khoảng thời gian cụ thể trôi qua mà không phát xạ nguồn khác


0

Bạn không thể nhận được một tham số từ RouterState nếu nó không được xác định trong tuyến đường, vì vậy trong ví dụ của bạn, bạn phải phân tích chuỗi truy vấn ...

Đây là mã tôi đã sử dụng:

let re = /[?&]([^=#&]+)=([^&#]*)/g;
let match;
let isMatch = true;
let matches = [];
while (isMatch) {
    match = re.exec(window.location.href);
    if (match !== null) {
        matches[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
        if (match.index === re.lastIndex) {
            re.lastIndex++;
        }
    }
    else {
        isMatch = false;
    }
}
console.log(matches);


0

Truy vấn và đường dẫn (Góc 8)

Nếu bạn có url như https://myapp.com/owner/123/show?height=23 thì hãy sử dụng

combineLatest( [this.route.paramMap, this.route.queryParamMap] )
  .subscribe( ([pathParams, queryParams]) => {
    let ownerId = pathParams.get('ownerId');    // =123
    let height  = queryParams.get('height');    // =height
    // ...
  })

CẬP NHẬT

Trong trường hợp khi bạn sử dụng this.router.navigate([yourUrl]);và các tham số truy vấn của bạn được nhúng trong yourUrlchuỗi thì góc sẽ mã hóa một URL và bạn nhận được một cái gì đó như thế này https://myapp.com/owner/123/show%3Fheight%323 - và giải pháp trên sẽ cho kết quả sai ( queryParams sẽ trống và tham số truy vấn có thể được dán vào param đường dẫn cuối cùng nếu nó ở cuối đường dẫn). Trong trường hợp này thay đổi cách điều hướng đến này

this.router.navigateByUrl(yourUrl);
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.