5

Сommon approach to process http response is like that:

return this._http.get(url)
           .map((res: Response) => res.json());

which provides you with an Observable<Object[]> where Object is dynamically created type from json de-serialization. Then you can use this result in *ngFor="let item of result | async" etc...

I'd like to get a specific type instance (meaning using new operator to call the type's constructor). Tried different ways to achieve something like that:

.map((res: Response) => { let obj = res.json(); return new MyObject(obj.id, obj.name);})

but getting this error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

This way seems to work but it's way too complicated and probably not effective:

.map((res: Response) => {
    let results = <MyObject[]>[];
    let obj = res.json();
    obj.forEach(
        function (o: any) {
            results.push(new MyObject(o.id, o.name));
        }
    );
    return results;
}

Thanks!

rook
  • 2,819
  • 4
  • 25
  • 41

3 Answers3

2

If you know what type of objects you want to deconstruct from the JSON (which you probably do) you can create a static method that returns an instance from Object.

class MyClass {

  prop: number;

  static fromObject(src: Object) {
    var obj = new MyClass();
    obj.prop = src.prop;
    return obj;
  }
}

Then convert the JSON response to instances of MyClass:

Rx.Observable.of('[{"prop":1},{"prop":2},{"prop":3}]')
  .map(val => JSON.parse(val))
  .exhaustMap(val => new Rx.Observable.from(val))
  .map(val => MyClass.fromObject(val))
  .subscribe(
    item => console.log('Next: ', item),
    error => console.log('Error:', error),
    _ => console.log('Completed')
  );

How this works:

  1. .map(val => JSON.parse(val)) Just converts the response to JSON which is an array of objects.

  2. .exhaustMap(val => new Rx.Observable.from(val)) Converts each value to an Observable and exhaustMap flattens them so each object from the JSON will be emitted separately.

  3. .map(val => MyClass.fromObject(val)) Use map again to convert each Object to an instance of MyClass.

See live demo: http://jsfiddle.net/f5k9zdh1/1/

martin
  • 93,354
  • 25
  • 191
  • 226
  • Interesting. Still too much code to my taste ;) but I'll take a deeper look. Thanks. – rook Sep 11 '16 at 18:46
2
.map((res: Response) => res.json().map(obj => new MyObject(obj.id, obj.name)))
James A Mohler
  • 11,060
  • 15
  • 46
  • 72
lps540
  • 29
  • 1
  • 6
    Code-only answer are not helpful. Please attempt to explain how your code solves OP's problem. Others who find this question through search may not be as experienced as you; help them understand your answer. – ad absurdum Jan 05 '17 at 05:23
0

Try this syntax, you cast it to your object:

 this.http.post(this.constants.taskUrl + parm, { headers: headers })
            .map((response: Response) => {
                var res = response.json();
                var result = <DataResponseObject>response.json();
                return result;
            })
John Baird
  • 2,606
  • 1
  • 14
  • 33
  • The deal here is that `response.json()` gives you an array of objects. I updated my question with the way that seems to work but I don't like that way. – rook Sep 10 '16 at 21:53