在Observable订阅中使用嵌套映射-Angular6

时间:2018-10-10 16:38:56

标签: javascript arrays angular rxjs

我正在通过API调用(在我的dataservicse.ts文件中)获取一些数据-得到的响应是一种复杂的JSON结构。我可以在相应的Component文件中按如下方式获取响应的特定部分-

这是代表一般结构的JSON对象响应之一-

{
    "address": {
        "building": "1234",
        "coord": [0, 0],
        "street": "123 Main Street",
        "zipcode": "00000"
    },
    "address2": "Test Suite 000",
    "grades": [{
        "grade": "A",
        "score": 3
    }, {
        "grade": "B",
        "score": 4
    }, {
        "grade": "A",
        "score": 2
    }],
    "name": "John Doe",
    "_id": "1212121"
}

现在-我的目标是从每个响应对象中获取'name'属性以及grades属性中的第一个'grade'值-并将它们映射到单独的数组中,以便可以使用*在表列中显示它们ngFor。

这是我的组件代码

export class TestDataComponent implements OnInit {

name$: Object;
grade$: Object;

constructor(private data: DataService, private data2: DataService) { }

ngOnInit() {
   //getAPIData is returning the API response from the dataservices.ts file
   this.data.getAPIData().subscribe(
       data=>console.log(data.response.map(name=>name.name))
       ); //this works fine - I get the names in an array

     this.data2.getAPIData().subscribe(
     data2=>console.log((data2.response.map(grade=>grade.grades)).map(grades 
        => {grades.map((value, index) => value.grade})) //this returns an undefined value
  );
 }

现在-如果我console.log((data2.response.map(grade=>grade.grades)) 我得到一个Array对象数组,例如-

Array - [Array(3), Array(3), Array(2)]

,它们每个都由“等级”属性“对象数组”组成。 (从上方获取第一个数组)-

Array(3)
0:{"grade": "A","score": 3}
1:{"grade": "B", "score": 4}
2:{"grade": "A", "score": 2}

因此-我进一步映射了我的初始响应以实现“等级”值。另外-我只想要一年级-因此我添加了一个简单的条件,如下所示-

console.log((data2.response.map(grade=>grade.grades))
              .map(grades 
                  => {grades.map((value, index) =>{if(index<1) value.grade})}))

如评论中所述-我得到一个未定义的值。

我无法理解这个问题可能很复杂,但是我已尽力尽可能清楚地解释了这个问题。我的目标是从每个对象中获取第一个“等级”值并将它们显示在数组中-就像名称一样,以便我可以使用它在表格上显示它。

我对Angular6还是很陌生,只是从Angular 1.6切换了-所以我很确定自己搞砸了。

通过订阅中的嵌套映射将成绩值放入数组的最佳方法是什么?还是有更好的方法来解决这个问题?

-为了简单起见,请忽略存在第一个订阅(针对name属性)的事实-我在这里进行了显示,以便明确我想要实现的目标。

2 个答案:

答案 0 :(得分:2)

这是我要的,因为您从未给出要映射/归约的具体示例。此外,这是原始的JavaScript,但可以轻松转换为RxJS。

// I am assuming that a call to `DataServce.getAPIData()` returns an array
const api_response = [{
    "address": {
        "building": "1234",
        "coord": [0, 0],
        "street": "123 Main Street",
        "zipcode": "00000"
    },
    "address2": "Test Suite 000",
    "grades": [{
        "grade": "A",
        "score": 3
    }, {
        "grade": "B",
        "score": 4
    }, {
        "grade": "A",
        "score": 2
    }],
    "name": "John Doe",
    "_id": "1212121"
}];

// Map and pluck the values you need
const result = api_response.map(v => [v.name, v.grades[0].score])

// Or as an array of objects
const obj_result = result.map(([name, score]) => ({ name, score }))

// Is this what you want?
console.log('Array', result);
console.log('Objects', obj_result);

快速更新

感谢您接受答案。只是想快速介绍一下使用RxJS的外观。我说可能是因为下面的代码段未经测试。

this.nameAndScores$ = data.getAPIData().pipe(
  map(({ response }) => response),
  map(({ name, grades }) => ( { name, score: grades[0].score } ))
)

假设nameAndScores$是组件实例的属性,则可以执行*ngFor item in nameAndScores$ | async并避免在代码中进行任何明确的预订。

答案 1 :(得分:0)

您正在第二个地图功能中使用带有粗箭头的花括号。使用花括号时,应使用return关键字返回一个值。