在 Angular2 中展平嵌套订阅

Flatten Nested Subscriptions in Angular2

在 Angular2 组件中,我订阅 activatedRoute 并使用其中一个路由参数发出 HTTP get 请求。

看来我需要同时订阅 activatedRoute.paramshttp.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`
  });