在 Angular2 中展平嵌套订阅
Flatten Nested Subscriptions in Angular2
在 Angular2 组件中,我订阅 activatedRoute
并使用其中一个路由参数发出 HTTP get
请求。
看来我需要同时订阅 activatedRoute.params
和 http.get
Observable——后者嵌套在前者中。
实际上我正在嵌套我的订阅,我确信它可以(并且应该)被压平。
我相信我可以为此使用 RxJs,但我不是专家!
以下组件有效,但我相信还可以改进。非常感谢您的建议!
import { Component, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ActivatedRoute } from '@angular/router';
import {
AngularFireDatabase,
FirebaseListObservable
} from 'angularfire2/database';
import * as firebase from 'firebase/app';
import { GridService } from '../grid.service';
import { SquareMetadata } from '../square-metadata';
import { SquareService } from '../square.service';
@Component({
selector: 'pu-grid',
templateUrl: './grid.component.html',
styleUrls: ['./grid.component.scss']
})
export class GridComponent implements OnInit {
public list: FirebaseListObservable<SquareMetadata[]>;
constructor(
private activatedRoute: ActivatedRoute,
private gridService: GridService,
private http: Http,
private squareService: SquareService
) {}
ngOnInit() {
this.activatedRoute.params.subscribe((params) => {
this.http.get('https://pu2-dev.firebaseio.com/squareMetadata/' + params.key + '.json?shallow=true')
.map((response: Response) => {
return response.json();
})
.subscribe((keys: Array<string>) => {
console.log(keys);
}, (error) => {
console.log(error);
});
this.gridService.activatedGrid = params.key;
this.list = this.squareService.list;
});
}
}
更新(基于atomrc的回答):
我已经根据 atomrc 的 回答重构了我的 ngOnInit
函数,但我现在收到一个错误,当导航到使用该组件的路由时应用程序失败。
到目前为止,这是我的重构:
ngOnInit() {
this.activatedRoute.params.mergeMap((params: Params) => {
return this.http.get('https://pu2-dev.firebaseio.com/squareMetadata/-KnGq1D89F4pdCH_vjhs.json?shallow=true')
})
.map((response: Response) => {
return response.json();
})
.subscribe((keys: Array<string>) => {
console.log(keys);
}, (error) => {
console.log(error);
});
}
我收到错误:
Error: Uncaught (in promise): TypeError: undefined is not a function (near '....map(function (response)...')
此外,如果您在我的原始代码中注意到,在 activatedRoute.params
订阅的底部我有行 this.gridService.activatedGrid = params.key;
在重构中,这需要移至订阅成功回调中。但是 params.key
在那里不可用。
因此我觉得这毕竟不是我想要的解决方案。
感谢您迄今为止的帮助!
更新:工作:-)
为了将来参考,以下是我的工作重构:
import { Component, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ActivatedRoute, Params, Router } from '@angular/router';
import {
AngularFireDatabase,
FirebaseListObservable
} from 'angularfire2/database';
import * as firebase from 'firebase/app';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import { GridService } from '../grid.service';
import { Shallow } from '../shallow';
import { SquareMetadata } from '../square-metadata';
import { SquareService } from '../square.service';
import { environment } from '../../environments/environment';
@Component({
selector: 'pu-grid',
templateUrl: './grid.component.html',
styleUrls: ['./grid.component.scss']
})
export class GridComponent implements OnInit {
public list: FirebaseListObservable<SquareMetadata[]>;
constructor(
private activatedRoute: ActivatedRoute,
private gridService: GridService,
private http: Http,
private router: Router,
private squareService: SquareService
) {}
ngOnInit() {
this.activatedRoute.params.mergeMap((params: Params) => {
let path: string = [
environment.firebaseAppConfig.databaseURL,
'squareMetadata',
params.key
].join('/');
return this.http.get([ path, '.json?shallow=true' ].join(''))
.map((response: Response) => {
return response.json();
})
.map((json: Shallow) => {
return { key: params.key, json: json };
});
})
.subscribe(({ key, json }: { key: string, json: Shallow }) => {
if (json) {
this.gridService.activatedGrid = key;
this.list = this.squareService.list;
} else {
this.router.navigate([ '' ]);
}
}, (error: Error) => {
throw new Error(error.message);
});
}
}
你完全正确,扁平化是这里要做的事情:)
对于 rxjs,您正在寻找的运算符是 mergeMap
。
这是您可以做的
this.activatedRoute.params
.mergeMap((params) => {
return this.http.get('https://example.com/' + params.key)
.map(response => response.json())
// build a new object from the response's data and the params
.map(data => ({ params: params, data: data }))
})
.subscribe(({ params, data }) => {
this.gridService.activatedGrid = params.key;
// do stuff with `data`
});
在 Angular2 组件中,我订阅 activatedRoute
并使用其中一个路由参数发出 HTTP get
请求。
看来我需要同时订阅 activatedRoute.params
和 http.get
Observable——后者嵌套在前者中。
实际上我正在嵌套我的订阅,我确信它可以(并且应该)被压平。
我相信我可以为此使用 RxJs,但我不是专家!
以下组件有效,但我相信还可以改进。非常感谢您的建议!
import { Component, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ActivatedRoute } from '@angular/router';
import {
AngularFireDatabase,
FirebaseListObservable
} from 'angularfire2/database';
import * as firebase from 'firebase/app';
import { GridService } from '../grid.service';
import { SquareMetadata } from '../square-metadata';
import { SquareService } from '../square.service';
@Component({
selector: 'pu-grid',
templateUrl: './grid.component.html',
styleUrls: ['./grid.component.scss']
})
export class GridComponent implements OnInit {
public list: FirebaseListObservable<SquareMetadata[]>;
constructor(
private activatedRoute: ActivatedRoute,
private gridService: GridService,
private http: Http,
private squareService: SquareService
) {}
ngOnInit() {
this.activatedRoute.params.subscribe((params) => {
this.http.get('https://pu2-dev.firebaseio.com/squareMetadata/' + params.key + '.json?shallow=true')
.map((response: Response) => {
return response.json();
})
.subscribe((keys: Array<string>) => {
console.log(keys);
}, (error) => {
console.log(error);
});
this.gridService.activatedGrid = params.key;
this.list = this.squareService.list;
});
}
}
更新(基于atomrc的回答):
我已经根据 atomrc 的 回答重构了我的 ngOnInit
函数,但我现在收到一个错误,当导航到使用该组件的路由时应用程序失败。
到目前为止,这是我的重构:
ngOnInit() {
this.activatedRoute.params.mergeMap((params: Params) => {
return this.http.get('https://pu2-dev.firebaseio.com/squareMetadata/-KnGq1D89F4pdCH_vjhs.json?shallow=true')
})
.map((response: Response) => {
return response.json();
})
.subscribe((keys: Array<string>) => {
console.log(keys);
}, (error) => {
console.log(error);
});
}
我收到错误:
Error: Uncaught (in promise): TypeError: undefined is not a function (near '....map(function (response)...')
此外,如果您在我的原始代码中注意到,在 activatedRoute.params
订阅的底部我有行 this.gridService.activatedGrid = params.key;
在重构中,这需要移至订阅成功回调中。但是 params.key
在那里不可用。
因此我觉得这毕竟不是我想要的解决方案。
感谢您迄今为止的帮助!
更新:工作:-)
为了将来参考,以下是我的工作重构:
import { Component, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ActivatedRoute, Params, Router } from '@angular/router';
import {
AngularFireDatabase,
FirebaseListObservable
} from 'angularfire2/database';
import * as firebase from 'firebase/app';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import { GridService } from '../grid.service';
import { Shallow } from '../shallow';
import { SquareMetadata } from '../square-metadata';
import { SquareService } from '../square.service';
import { environment } from '../../environments/environment';
@Component({
selector: 'pu-grid',
templateUrl: './grid.component.html',
styleUrls: ['./grid.component.scss']
})
export class GridComponent implements OnInit {
public list: FirebaseListObservable<SquareMetadata[]>;
constructor(
private activatedRoute: ActivatedRoute,
private gridService: GridService,
private http: Http,
private router: Router,
private squareService: SquareService
) {}
ngOnInit() {
this.activatedRoute.params.mergeMap((params: Params) => {
let path: string = [
environment.firebaseAppConfig.databaseURL,
'squareMetadata',
params.key
].join('/');
return this.http.get([ path, '.json?shallow=true' ].join(''))
.map((response: Response) => {
return response.json();
})
.map((json: Shallow) => {
return { key: params.key, json: json };
});
})
.subscribe(({ key, json }: { key: string, json: Shallow }) => {
if (json) {
this.gridService.activatedGrid = key;
this.list = this.squareService.list;
} else {
this.router.navigate([ '' ]);
}
}, (error: Error) => {
throw new Error(error.message);
});
}
}
你完全正确,扁平化是这里要做的事情:)
对于 rxjs,您正在寻找的运算符是 mergeMap
。
这是您可以做的
this.activatedRoute.params
.mergeMap((params) => {
return this.http.get('https://example.com/' + params.key)
.map(response => response.json())
// build a new object from the response's data and the params
.map(data => ({ params: params, data: data }))
})
.subscribe(({ params, data }) => {
this.gridService.activatedGrid = params.key;
// do stuff with `data`
});