Ionic:操纵通过IonicSuper启动器模板

时间:2018-04-19 22:15:42

标签: angular rest typescript rxjs ionic3

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

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

我似乎无法理解返回结果的类型以及如何操作它。我要说,我对应用程序开发没有多少经验,更不用说TypeScript及其变体了。但我的理解是RxJS提供了一个允许certain operations on the resulting data的Observable数据类型。但是当我使用所述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. 另外:分享()的作用是什么?我在HttpClient代码中找不到任何对此的引用。
  3. 如果需要其他信息,我会编辑这篇文章。

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

    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中的数据。但我想,在处理Observable时,已经存在这种交互的实现,特别是在尝试根据其属性过滤响应数据时。 或者我是否必须为此创建自己的实现?考虑到可以直接在简单的单行评估上过滤元素,这听起来是错误的。但我可能会在这里误读一些东西。

    响应机构如下。每个预测都是一个对象。

    [
      {
        "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响应之前我已经过滤服务器端。但对于很多用例而言,这似乎效率低下。我无法想象不存在这种情况的实施。

    我错过了什么?

1 个答案:

答案 0 :(得分:1)

这里有很多事情发生,所以我会尽力将其分解。

RxJS Lettable Operators(可能无法找到您的运营商的原因)

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()将产生一个&#34;可观察序列,其中包含通过组播源序列产生的序列的元素。&#34; https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/share.md

阵列缓冲区

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

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