【问题标题】:Ionic: Manipulate the GET request result retrieved via REST API handler of the IonicSuper starter templateIonic:操作通过 IonicSuper 起始模板的 REST API 处理程序检索到的 GET 请求结果
【发布时间】:2018-09-30 13:03:04
【问题描述】:

我在处理 GET 请求的结果元素时遇到问题。

应用正在使用IonicSuper starter template 构建,并使用该模板中附带的REST API handler

我似乎无法理解返回结果的类型以及如何操作它。我得说,我在应用程序开发方面没有太多经验,更不用说 TypeScript 及其变体了。但我的理解是 RxJS 提供了一个 Observable 数据类型,它允许certain operations on the resulting data。但是,当我使用所述 API 处理程序时,这些都不起作用。
我在各种网站上搜索了解决方案,但没有一个合适。在我所见之处,基本的 Angular HttpClient 与 RxJS Observable 结合使用。由于我使用的是 IonicSuper 模板,因此我也想使用包含的 REST API 处理程序。但是我无法从它的代码和文档中检索到我需要的信息。

我的目标是从给定 id 指定的一组对象中获取单个对象(或者:一个仅包含一个对象的数组)。以下是我的 provider.ts 的相关部分:

import { Injectable }   from '@angular/core';

import { Api }                      from '../api/api';
import 'rxjs/add/operator/filter';

import { tPrediction }              from '../../models/prediction';

@Injectable()
export class Prediction {
    //API endpoint: Predictions
    private epPredictions = 'predictions';

    constructor(private api: Api) { }

    getPrediction(id: number) {
        let seq = this.api
            .get(this.epPredictions)
//          .flatMap((response) => response.json())
            .filter(prediction => prediction.id == id)
            .share();

        seq.subscribe((res: any) => {
            console.debug('prediction id', id);
            console.debug('res', res);
        }, err => {
            this.handleError(err);
        });
        return seq;
    }
}

现在,flatMap() 和 filter() 都会产生 TypeScript 错误Property '(flatMap|filter)' does not exist on type 'Observable<ArrayBuffer>'.

这就是我迷路的地方:我是这样理解的,http.get() 返回一个 Observable 并且应该使用这些运算符。显然不是这样的。

我也尝试过提供一个函数,类似于RxJS docs:

let seq = this.api
    .get(this.epPredictions)
    //          .flatMap((response) => response.json())
    .filter(function(prediction, idx) {
        console.debug('getPrediction id', id);
        console.debug('getPrediction prediction.id', prediction["id"]);

        return prediction["id"] == id;
    })
    .share();

也不起作用,因为 prediction["id"] 未定义。

我很难理解这种 ArrayBuffer 类型的工作原理以及我可以用它做什么。

  1. 所以我的主要问题是:如何访问/操作结果?到目前为止,我只能将结果数组作为一个整体返回,而不是它的特定部分。
  2. 另外:这个 share() 有什么作用?我在 HttpClient 代码中找不到对此的任何引用。

如果需要更多信息,我会编辑这篇文章。

感谢您阅读本文以及您提供的任何知识。

PS:我知道我可以让服务器通过将 ID 作为附加 GET 参数来进行过滤,这最终可能会发生。但因为这是我试图理解的一个非常基本的问题,所以我想在处理当前任务的同时立即解决这个问题。


编辑

我制作了一个项目副本并将 RxJS 包更新到版本 5.5.10(在 5.5.7 上)。提供者现在正在使用 .pipe(),但它仍然无法访问 prediction.id,因为它正在处理 ArrayBuffer。

这是当前的 getPrediction():

getPrediction(id: number) {
    var predictions = this.api.get(this.epPredictions);
console.debug('pipe');
    var seq = predictions.pipe(
        filter(function(prediction, i){
            console.debug('prediction', prediction);
            return prediction.id === id;
        })
    );
    seq.subscribe((res: any) => {
        console.debug('prediction id', id);
        console.debug('res', res);
    }, err => {
        this.handleError(err);
    });

    return seq;
}

这不起作用,因为Property 'id' does not exist on type 'ArrayBuffer'. 使用运算符与

相同
filter(prediction => prediction.id === id) 

相反。我知道我无法直接获取存储在 ArrayBuffer 中的数据。但我想,在处理 Observables 时,已经有了这种交互的实现,尤其是在尝试根据其属性过滤响应数据时。
还是我必须为此创建一个自己的实现?考虑到可以在简单的单行评估中直接过滤元素,这听起来是错误的。但我可能在这里误读了一些东西。

响应正文如下。每个预测都是一个对象。

[
  {
    "categories": [
      0,
      1
    ],
    "id": 1,
    "name": "Foo"
  },
  ...
]

更新

做了一些进一步的研究和反复试验,但我仍然无法过滤元素。 ArrayBuffer 类型阻止了我对元素的任何访问,这意味着我无法过滤它们。

我尝试在提供程序中将结果硬编码为可解析的 JSON,然后通过过滤器运算符访问 Observable:

var predictions = from([
    {categories:[0,1], id:1},
    {categories:[0,1], id:2},
    {categories:[0,2], id:3},
    {categories:[0,1], id:4},
    {categories:[0,1], id:5},
    {categories:[0,4], id:6},
    {categories:[0,1], id:7},
    {categories:[0,1], id:8},
    {categories:[0,1], id:9},
    {categories:[0,1], id:10},
    {categories:[0,1], id:11}
]);

var seq = predictions.pipe(
    filter(prediction => {
        //print every single prediction
        console.debug('prediction', prediction);
        return prediction;
    })
);

这按预期工作,每个对象都被读取并视为单个实体,这正是我想要的。

但是,如果我执行 GET 请求,则响应存储在 ArrayBuffer 类型中,这使得行为完全不同:

var predictions = this.http.get('http://localhost/myApi/predictions');

var seq = predictions.pipe(
    filter(function(prediction, i){
        //the whole array is printed
        console.debug('prediction', prediction);
        console.info('i', i);
        return true;
    })
);

因此,不是能够为自身读取每个元素,而只有整个数组可以被读取/打印。这是有道理的,因为据我所知,它是一个 ArrayBuffer,因此是一个字节流。但这使得无法读取该数组中的每个元素(即每个预测对象)并对其应用过滤器。

如何将 RxJS 的 filter() 或 map() 方法应用于这个 ArrayBuffer 的内容?或者我该如何转换这个 ArrayBuffer 才能做到这一点?

我越是尝试找到解决方案,我就越觉得自己必须在将 JSON 响应发送到应用程序之前过滤服务器端。但这对于很多用例来说似乎效率低下。而且我无法想象这种情况不会存在实现。

我错过了什么?

【问题讨论】:

    标签: angular rest typescript rxjs ionic3


    【解决方案1】:

    这里发生了很多事情,所以我会尽可能地分解它。

    RxJS Lettable 运算符(可能是它找不到您的运算符的原因)

    Property '(flatMap|filter)' does not exist on type 'Observable<ArrayBuffer> - 这可能是您当前版本的 RxJS 的问题。在最近的版本中,他们删除了这些可链接的方法,以采用更实用的方法。取而代之的是一个pipe 方法,它采用一系列函数来应用于事件流。这样你只需要导入你正在使用的东西——而不是整个 RxJS 库。在此处查看更多信息:https://hackernoon.com/rxjs-reduce-bundle-size-using-lettable-operators-418307295e85

    新 API 样式示例:

    this.api.get(this.epPredictions, {prediction_id: id})
        .pipe(filter(prediction.id === id), share())
    

    share() 有什么作用?

    share() 仅在您有多个订阅者时才有用——您在这里不需要它。默认情况下,当订阅一个 observable 时,它​​将获得自己的事件。这意味着如果您的 observable 被订阅了两次,那么您的 observable 可能会被执行两次,每个订阅者都会获得自己的事件。 share() 将向两个订阅者发送相同的事件并执行一次你的 observable。在 RxJS 中,这意味着share() 将产生一个“包含通过多播源序列产生的序列元素的可观察序列”。 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/share.md

    数组缓冲区

    引用 Mozilla 的话——“ArrayBuffer 是一种数据类型,用于表示通用的、固定长度的二进制数据缓冲区。您不能直接操作 ArrayBuffer 的内容;相反,您可以创建一个类型化的数组视图或以特定格式表示缓冲区的 DataView,并使用它来读取和写入缓冲区的内容。” https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays

    换句话说,ArrayBuffer 不是标准的 JS 数组——它是某种数据(如图像)的原始表示。需要有关其内容的更多信息才能正确回答您的问题。

    【讨论】:

    • 感谢您的全面回答和链接。这已经帮助我理解了我正在处理的事情。我仍然缺少一些东西,因为我仍然无法过滤请求结果。我将使用当前状态编辑我的问题,并提供有关结果数据的一些信息。
    • 我仍在努力解决这个问题。尝试了更多解决方案并测试了想法。问题是我无法访问那个ArrayBuffer 的内容。我发现没有解决方案或教程对它有帮助。更新了问题。
    • 听起来您需要返回与后端不同的东西。如果数据真的只是一个简单的 JSON 数组,则可能是您的标头中的 Content-Type 不正确。 Angular 应该自动解析 json 并在找到“Content-Type: 'application/json'” 标头时将其返回给您。
    • 标头设置正确:响应发送Content-Type: application/json; charset=UTF-8。 Firefox 的 Web 开发工具能够将整个结果解析为有效的 JSON,我也可以用它来检查响应内容。
    猜你喜欢
    • 2017-08-12
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多