首页 > 解决方案 > 尝试访问创建的新属性时未定义

问题描述

我做了很多研究,但我一直发现自己陷入了循环或死胡同。我正在向客户 API 发出请求。请求的结果有一些坐标,我使用反向地理编码来获取客户的地址。当我在我的组件中订阅时getCustomer(),我可以看到new_address但是console.log(customer),当我尝试深入了解我创建的新属性console.log(customer.items[0].new_Address)时返回undefined

问题是为什么会发生这种情况,以及如何解决。

第二个问题是,这可以通过MergeMap

getCustomer() {
    return this.http.get('api/customer').pipe(
        map((customer: any) => {
            customer.items.forEach(order => {
                this.getAddress(
                    customer.coordinates.lat,
                    customer.coordinates.long
                ).subscribe((location: any) => {
                    order.new_address = location.results[0]['formatted_address'];
                });
            }, customer.items);
            console.log(orders.items);
            return customer;
        }),
        catchError(error => {
            return throwError(error);
        })
    );
}

getAddress(lat, long) {
    return this.http.get(
        'https://maps.googleapis.com/maps/api/geocode/json?latlng=' +
        lat +
        ',' +
        long +
        '&key=xxx'
    );
}

根据我目前收到的回复,我更新了代码,纠正了一些语法错误,但仍然存在问题。其他操作员无法访问第一个返回的响应或第二个响应。我想知道如何解决这个问题。

这是客户 API 的返回结果

{

    "items": [{
        "customer": "Christopher Wallace",
        "coordinates": {
            "lat": 57.500069,
            "long": -0.13453099999999998
        }

    }, {
        "customer": "Amir Khani",
        "coordinates": {
            "lat": 58.500069,
            "long": -0.13453099999999998
        }
    }, {
        "customer": "Laporte Fishing",
        "coordinates": {
            "lat": 59.500069,
            "long": -0.13453099999999998
        }

    }]
}


//Approach used based on reply
getCustomer() {
    return this.http.get('api/customer').pipe(
      switchMap((customer : any) => this.getAddress(customer.items.coordinates.lat, customer.items.coordinates.long))).pipe(
    // customer is not accessible here, why?
    tap(address => customer.items.forEach(order => order.new_address = address)),
    // customer is not accessible either, why?
    mapTo(customer)
  )
}

这个想法是拥有我可以从我的组件订阅的结构。我上面的原始代码做到了这一点,但我无法获得新地址。

{

    "items": [
    {
        "customer": "Christopher Wallace",
        "coordinates": {
            "lat": 57.500069,
            "long": -0.13453099999999998
        },
        "new_address": "Abc street 1"
    }, 
    {
        "customer": "Amir Khani",
        "coordinates": {
            "lat": 58.500069,
            "long": -0.13453099999999998
        },
        "new_address": "Abc street 2"
    },
    {
        "customer": "Laporte Fishing",
        "coordinates": {
            "lat": 59.500069,
            "long": -0.13453099999999998
        },
        "new_address": "Abc street 3"
    }]
}

标签: angulartypescriptrxjsobservable

解决方案


我认为这样的事情应该适合你:

  getCustomer() {
    return this.http.getCustomer('api/customer').pipe(
      switchMap(customer => this.getAddress(customer.coordinates).pipe(
        tap(address =>
          customer.items.forEach(order => (order.new_address = address))
        ),
        mapTo(customer)
      )
    ));
  }
  • switchMap将处理订阅由getAddress().
  • tap是为了副作用,这有点像你通过修改数组元素所做的
  • mapTo总是返回提供的值

返回实际地址似乎很有帮助getAddress(),因此您无需挖掘它:

  getAddress(coordinates: Customer['coordinates']) {
    const { lat, long } = coordinates;
    const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${long}&key=key}`;

    return this.http.getLocation(url).pipe(
      map(location => location.results[0]['formatted_address'])
    );
  }

如果您想以不可变的方式处理数据,您可以返回一个全新的客户对象。在这种情况下,您可以只使用map而不是tapand mapTo

  getCustomer() {
    return this.http.getCustomer('api/customer').pipe(
      switchMap(customer => this.getAddress(customer.coordinates).pipe(
        map(address => ({
            ...customer,
            items: customer.items.map(order => ({
              ...order, 
              new_address: address
            }))
        }) as Customer)
      ))
    );
  }

推荐阅读