【发布时间】: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 类型的工作原理以及我可以用它做什么。
- 所以我的主要问题是:如何访问/操作结果?到目前为止,我只能将结果数组作为一个整体返回,而不是它的特定部分。
- 另外:这个 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