I have set up the following routing system
export const MyRoutes: Routes = [
{path: '', redirectTo: 'new', pathMatch: 'full'},
{path: ':type', component: MyComponent}
];
and have the following navigation system
goToPage('new');
goToPageNo('new', 2);
goToPage(type) {
this.router.navigate([type]);
}
goToPageNo(type, pageNo) {
this.router.navigate([type], {queryParams: {page: pageNo}});
}
Sample URL looks like this
http://localhost:3000/new
http://localhost:3000/new?page=2
http://localhost:3000/updated
http://localhost:3000/updated?page=5
Sometimes they have optional queryParams (page)
Now I need to read both route params and queryParams
ngOnInit(): void {
this.paramsSubscription = this.route.params.subscribe((param: any) => {
this.type = param['type'];
this.querySubscription = this.route.queryParams.subscribe((queryParam: any) => {
this.page = queryParam['page'];
if (this.page)
this.goToPageNo(this.type, this.page);
else
this.goToPage(this.type);
})
})
}
ngOnDestroy(): void {
this.paramsSubscription.unsubscribe();
this.querySubscription.unsubscribe();
}
Now this is not working as expected, visiting pages without queryParams works, then of I visit a page with queryParams "goToPageNo" gets called multiple times, as I am subscribing to queryParams inside route params.
I looked at the Angular 2 documentation, they do not have any example or codes where a subscription to both route params and queryParams is implemented at the same time.
Any way to do this properly? Any suggestions?
I managed to get a single subscription to both the queryParams and Params by combining the observables by using Observable.combineLatest
before subscribing.
Eg.
var obsComb = Observable.combineLatest(this.route.params, this.route.queryParams,
(params, qparams) => ({ params, qparams }));
obsComb.subscribe( ap => {
console.log(ap.params['type']);
console.log(ap.qparams['page']);
});
For Angular 6+
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
...
combineLatest(this.route.params, this.route.queryParams)
.pipe(map(results => ({params: results[0].xxx, query: results[1]})))
.subscribe(results => {
console.log(results);
});
Where xxx
is from your route
{path: 'post/:xxx', component: MyComponent},
Late answer, but another solution : Instead of subscribing to the params and queryparams I subscribe to the NavigationEnd event on the router. Fires only once and both params and queryparams are available on snapshot : (example for angular 4)
this.router.events.filter(event=>event instanceof NavigationEnd)
.subscribe(event=>{
let yourparameter = this.activatedroute.snapshot.params.yourparameter;
let yourqueryparameter = this.activatedroute.snapshot.queryParams.yourqueryparameter;
});
Regarding unsubscribing : yes it is true routing params, queryParams or navigation events subscriptions are automatically unsubscribed by the router, there is however one exception : if your route has children , when navigating between children, no unsubscribe will occur. Only when you navigate away from the parent route!
Eg I had a situation with tabs as child routes. In constructor of first tab component subscribing on route params to retrieve data. Each time I navigate from first to second tab and back another subscription was added resulting in multiplying the number of requests.
An alternative (on Angular 7+) is to subscribe to the ActivatedRoute url observable and use "withLatestFrom" to get the latest paramsMap and queryParamsMap. It appears that the params are set before the url observable emits:
this.route.url.pipe(
withLatestFrom(this.route.paramMap, this.route.queryParamMap)
).subscribe(([url, paramMap, queryParamMap]) => {
// Do something with url, paramsMap and queryParamsMap
});
https://rxjs-dev.firebaseapp.com/api/operators/withLatestFrom
The proposed solutions using combineLatest
do not work properly. After the first route change, you will get an event every time the param
or queryParam
value changes, which means you get calls in an intermediate state when one has changed but the other has not, very bad.
@rekna's solution pretty much works for me, except I wasn't getting an event when my app was first loaded, so here's my modification to @rekna's solution:
this.routeUpdate(this.activatedRoute.snapshot);
this.routeSubscription = this.router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe(event => this.routeUpdate(this.activatedRoute.snapshot));
Where routeUpdate
is a method to do whatever parameter handling is required.
Use ActivatedRouteSnapshot
from your ActivatedRoute
ActivatedRouteSnapshot
interface has params
and queryParams
property, and you could get the both value at the same time.
constructor(private route: ActivatedRoute) {
console.log(this.route.snapshot.params);
console.log(this.route.snapshot.queryParams);
}
Edit : As OP stated, we only get the initial value of the parameters with this technique.
Example Plunker
I think you should use zip operator https://www.learnrxjs.io/operators/combination/zip.html
Because if you use combineLatest and change url params or query params you got value with new query params and old url params.
Urls for example:
Shifatul's answer extended for ...
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
// ...
combineLatest([this.route.params, this.route.queryParams])
.subscribe(([params, queryParams]) => {
console.log("your route data:", params, queryParams);
});
I have set up the following routing system
export const MyRoutes: Routes = [
{path: '', redirectTo: 'new', pathMatch: 'full'},
{path: ':type', component: MyComponent}
];
and have the following navigation system
goToPage('new');
goToPageNo('new', 2);
goToPage(type) {
this.router.navigate([type]);
}
goToPageNo(type, pageNo) {
this.router.navigate([type], {queryParams: {page: pageNo}});
}
Sample URL looks like this
http://localhost:3000/new
http://localhost:3000/new?page=2
http://localhost:3000/updated
http://localhost:3000/updated?page=5
Sometimes they have optional queryParams (page)
Now I need to read both route params and queryParams
ngOnInit(): void {
this.paramsSubscription = this.route.params.subscribe((param: any) => {
this.type = param['type'];
this.querySubscription = this.route.queryParams.subscribe((queryParam: any) => {
this.page = queryParam['page'];
if (this.page)
this.goToPageNo(this.type, this.page);
else
this.goToPage(this.type);
})
})
}
ngOnDestroy(): void {
this.paramsSubscription.unsubscribe();
this.querySubscription.unsubscribe();
}
Now this is not working as expected, visiting pages without queryParams works, then of I visit a page with queryParams "goToPageNo" gets called multiple times, as I am subscribing to queryParams inside route params.
I looked at the Angular 2 documentation, they do not have any example or codes where a subscription to both route params and queryParams is implemented at the same time.
Any way to do this properly? Any suggestions?
Following Shifatul's answer, this supposes working for the observables changed at the same time and just fire once:
import { combineLatest } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
...
combineLatest(this.route.params, this.route.queryParams)
.pipe(map(results => ({params: results[0].xxx, query: results[1]})), debounceTime(0))
.subscribe(results => {
console.log(results);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.