Angular queryParamMap 为空,然后填充
Angular queryParamMap is empty, then populated
我在我的应用程序中创建了一个新模块,这样我就可以分离不需要通信的部分,并创建了一个 new.module.ts 具有自己的路由模块和组件:
new-routing.module.ts
:
const exportRoutes: Routes = [
{
path: 'export',
component: ExportsComponent
}
]
@NgModule({
imports: [RouterModule.forRoot(exportRoutes)],
exports: [RouterModule]
})
export class ExportRoutingModule {}
new.module.ts
:
import { Router } from '@angular/router'
import { BrowserModule } from '@angular/platform-browser'
// Routing Module
import { NewRoutingModule } from './new-routing.module'
@NgModule({
imports: [..., ExportRoutingModule, ...],
declarations: [ExportsComponent],
bootstrap: [ExportsComponent]
})
我有一个简单的index.html
:
<body class="app">
<router-outlet></router-outlet> // outlet is here because I read that I needed it to be able to use activated route, I actually just want the query params
</body>
最后,问题出在哪里,我的组件:
export class MyComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit() {this.activatedRoute.queryParamMap.subscribe(
(params: ParamMap) => console.log(params)
// Do stuff with params => error)}
当我在我的控制台中导航到 http://localhost:4200/export?firstParam=1.00,2.00,3.00
时,params
被记录了两次,一次为空,一次如此填充:
ParamsAsMap {params: {…}}
keys:(...) // empty
params:{} // empty
core.js:3565 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
ParamsAsMap {params: {…}}
keys:Array(3)
params:{firstParam: "1.00,2.00,3.00", secondParam: "bla"}
这会导致我的组件抛出错误,因为我需要这些参数来显示我的组件,而第一次登录时它们是空的,所以:
- 为什么他们登录了两次?
- 为什么我的代码在我的 params observable 有值之前执行?
- 我能去掉路由器插座吗(我真的不需要,因为我没有路由涉及这个模块,我只是用它,因为我读到我不能使用
activatedRoute
没有它;我只想要 url 中的查询参数
感谢您的帮助
我认为问题在于您正在使用 ExportsComponent
进行引导:
@NgModule({
...
bootstrap: [ExportsComponent]
})
您在此处指定的组件在应用程序启动时使用,因此它ngOnInit
会提前调用。
你可以做的是有一个单独的组件用于引导和单独的ExportComponent
,这是一个例子(参见the live version):
import { bootstrap } from '@angular/platform-browser-dynamic';
import { RouterModule, Router, Routes, ActivatedRoute } from '@angular/router';
import { NgModule, Component, OnInit } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
@Component({
selector: 'my-app',
template: `
<nav class="rbe-plunk-nav">
<ul>
<li> <a [routerLink]="['/']">Homepage</a> </li>
<li> <a [routerLink]="['/about']">Export</a> </li>
</ul>
</nav>
<main>
<router-outlet></router-outlet>
<!-- The router will put the content here, right after the outlet -->
</main>
`
})
export class AppComponent { }
@Component({
selector: 'home',
template: '<h1>Home: </h1>'
})
export class HomeComponent { }
@Component({
selector: 'export',
template: '<h1>Export: </h1>'
})
export class ExportComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.queryParamMap.subscribe(paramMap => {
console.log("Export: ");
console.log(paramMap);
});
}
}
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: ExportComponent }
];
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(
routes,
{ /*enableTracing: true*/ }
)
],
declarations: [
AppComponent,
HomeComponent,
ExportComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule {
// Diagnostic only: inspect router configuration
constructor(router: Router) {
console.log('Routes: ', JSON.stringify(router.config, undefined, 2));
}
}
platformBrowserDynamic().bootstrapModule(AppModule);
我将针对这个问题提供 2 个解决方案,首先,使用 skip
运算符:
因为 Activated Route 是一个 BehaviorSubject,所以首先我们会得到一个空值,然后是实际的查询参数,这样我们就可以跳过第一个值:
(注意,此解决方案使用可出租运算符,因此 pipe()
,如果您不使用可出租运算符,您可以像使用任何其他 rxjs 运算符一样链接它:.skip(1)
export class MyComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit()
{this.activatedRoute.queryParamMap.pipe(skip(1)).subscribe(
(params: ParamMap) => console.log(params)}
第二种解决方案,使用常规 javascript 函数来检索参数:
ngOnInit() {
const token = this.getParameterByName('access_token');
console.log(token);
}
getParameterByName(name: any) {
let url = window.location.href;
name = name.replace(/[[]]/g, "$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/+/g, " "));
}
我会把你指向这个 Whosebug answer 的原始代码
Url: http://localhost:4200/licenca-filtro?param=60¶m2=50
component.ts
constructor(
private route: ActivatedRoute,
) {
const param1 = this.route.queryParams['value']['param'];
const param2 = this.route.queryParams['value']['param2'];
console.log(param1, param2);
}
输出:60 50
@Lakston 接受的答案没有考虑没有查询参数时的流程,我们需要检测它。经过一番努力后,我为我们这些使用 SSR(服务器端渲染,意味着我们没有可用的浏览器全局对象)并且需要检测无查询参数场景的人找到了一个真正的解决方案。
import { Location } from '@angular/common';
----------------------------------------------------------
constructor(private location: Location)
----------------------------------------------------------
let questionIndex = this.location.path().indexOf('?');
questionIndex = questionIndex === -1 ? Infinity : questionIndex;
const queryParams = (<any>Object).fromEntries(this.location.path().substr(questionIndex + 1).split('&').filter(str => str).map(el => el.split('=')));
所有致谢 YugasVasyl,他将此答案发布于:https://github.com/angular/angular/issues/12157
我已经在我的项目中对其进行了测试并且它有效!
祝福...
我在我的应用程序中创建了一个新模块,这样我就可以分离不需要通信的部分,并创建了一个 new.module.ts 具有自己的路由模块和组件:
new-routing.module.ts
:
const exportRoutes: Routes = [
{
path: 'export',
component: ExportsComponent
}
]
@NgModule({
imports: [RouterModule.forRoot(exportRoutes)],
exports: [RouterModule]
})
export class ExportRoutingModule {}
new.module.ts
:
import { Router } from '@angular/router'
import { BrowserModule } from '@angular/platform-browser'
// Routing Module
import { NewRoutingModule } from './new-routing.module'
@NgModule({
imports: [..., ExportRoutingModule, ...],
declarations: [ExportsComponent],
bootstrap: [ExportsComponent]
})
我有一个简单的index.html
:
<body class="app">
<router-outlet></router-outlet> // outlet is here because I read that I needed it to be able to use activated route, I actually just want the query params
</body>
最后,问题出在哪里,我的组件:
export class MyComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit() {this.activatedRoute.queryParamMap.subscribe(
(params: ParamMap) => console.log(params)
// Do stuff with params => error)}
当我在我的控制台中导航到 http://localhost:4200/export?firstParam=1.00,2.00,3.00
时,params
被记录了两次,一次为空,一次如此填充:
ParamsAsMap {params: {…}}
keys:(...) // empty
params:{} // empty
core.js:3565 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
ParamsAsMap {params: {…}}
keys:Array(3)
params:{firstParam: "1.00,2.00,3.00", secondParam: "bla"}
这会导致我的组件抛出错误,因为我需要这些参数来显示我的组件,而第一次登录时它们是空的,所以:
- 为什么他们登录了两次?
- 为什么我的代码在我的 params observable 有值之前执行?
- 我能去掉路由器插座吗(我真的不需要,因为我没有路由涉及这个模块,我只是用它,因为我读到我不能使用
activatedRoute
没有它;我只想要 url 中的查询参数
感谢您的帮助
我认为问题在于您正在使用 ExportsComponent
进行引导:
@NgModule({
...
bootstrap: [ExportsComponent]
})
您在此处指定的组件在应用程序启动时使用,因此它ngOnInit
会提前调用。
你可以做的是有一个单独的组件用于引导和单独的ExportComponent
,这是一个例子(参见the live version):
import { bootstrap } from '@angular/platform-browser-dynamic';
import { RouterModule, Router, Routes, ActivatedRoute } from '@angular/router';
import { NgModule, Component, OnInit } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
@Component({
selector: 'my-app',
template: `
<nav class="rbe-plunk-nav">
<ul>
<li> <a [routerLink]="['/']">Homepage</a> </li>
<li> <a [routerLink]="['/about']">Export</a> </li>
</ul>
</nav>
<main>
<router-outlet></router-outlet>
<!-- The router will put the content here, right after the outlet -->
</main>
`
})
export class AppComponent { }
@Component({
selector: 'home',
template: '<h1>Home: </h1>'
})
export class HomeComponent { }
@Component({
selector: 'export',
template: '<h1>Export: </h1>'
})
export class ExportComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.queryParamMap.subscribe(paramMap => {
console.log("Export: ");
console.log(paramMap);
});
}
}
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: ExportComponent }
];
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(
routes,
{ /*enableTracing: true*/ }
)
],
declarations: [
AppComponent,
HomeComponent,
ExportComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule {
// Diagnostic only: inspect router configuration
constructor(router: Router) {
console.log('Routes: ', JSON.stringify(router.config, undefined, 2));
}
}
platformBrowserDynamic().bootstrapModule(AppModule);
我将针对这个问题提供 2 个解决方案,首先,使用 skip
运算符:
因为 Activated Route 是一个 BehaviorSubject,所以首先我们会得到一个空值,然后是实际的查询参数,这样我们就可以跳过第一个值:
(注意,此解决方案使用可出租运算符,因此 pipe()
,如果您不使用可出租运算符,您可以像使用任何其他 rxjs 运算符一样链接它:.skip(1)
export class MyComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit()
{this.activatedRoute.queryParamMap.pipe(skip(1)).subscribe(
(params: ParamMap) => console.log(params)}
第二种解决方案,使用常规 javascript 函数来检索参数:
ngOnInit() {
const token = this.getParameterByName('access_token');
console.log(token);
}
getParameterByName(name: any) {
let url = window.location.href;
name = name.replace(/[[]]/g, "$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/+/g, " "));
}
我会把你指向这个 Whosebug answer 的原始代码
Url: http://localhost:4200/licenca-filtro?param=60¶m2=50
component.ts
constructor(
private route: ActivatedRoute,
) {
const param1 = this.route.queryParams['value']['param'];
const param2 = this.route.queryParams['value']['param2'];
console.log(param1, param2);
}
输出:60 50
@Lakston 接受的答案没有考虑没有查询参数时的流程,我们需要检测它。经过一番努力后,我为我们这些使用 SSR(服务器端渲染,意味着我们没有可用的浏览器全局对象)并且需要检测无查询参数场景的人找到了一个真正的解决方案。
import { Location } from '@angular/common';
----------------------------------------------------------
constructor(private location: Location)
----------------------------------------------------------
let questionIndex = this.location.path().indexOf('?');
questionIndex = questionIndex === -1 ? Infinity : questionIndex;
const queryParams = (<any>Object).fromEntries(this.location.path().substr(questionIndex + 1).split('&').filter(str => str).map(el => el.split('=')));
所有致谢 YugasVasyl,他将此答案发布于:https://github.com/angular/angular/issues/12157
我已经在我的项目中对其进行了测试并且它有效! 祝福...