Jenthe Jenthe - 1 month ago 12
AngularJS Question

Angular 2 observable doesn't 'map' to model

As I'm learning Angular 2 I used an observable to fetch some data via an API. Like this:

getPosts() {
return this.http.get(this._postsUrl)
.map(res => <Post[]>res.json())
.catch(this.handleError);
}


My post model looks is this:

export class Post {

constructor(
public title: string,
public content: string,
public img: string = 'test') {
}


The problem I'm facing is that the map operator doesn't do anything with the Post model. For example, I tried setting a default value for the img value but in the view post.img displays nothing. I even changed Post[] with an other model (Message[]) and the behaviour doesn't change. Can anybody explain this behaviour?

Answer

I had a similar issue when I wanted to use a computed property in a template.

I found a good solution in this article:

http://chariotsolutions.com/blog/post/angular-2-beta-0-somnambulant-inauguration-lands-small-app-rxjs-typescript/

You create a static method on your model that takes an array of objects and then call that method from the mapping function. In the static method you can then either call the constructor you've already defined or use a copy constructor:

Mapping Method

getPosts() {
  return this.http.get(this._postsUrl)
    .map(res => Post.fromJSONArray(res.json()))
    .catch(this.handleError);
}

Existing Constructor

export class Post {
  // Existing constructor.
  constructor(public title:string, public content:string, public img:string = 'test') {}

  // New static method.
  static fromJSONArray(array: Array<Object>): Post[] {
    return array.map(obj => new Post(obj['title'], obj['content'], obj['img']));
  }
}

Copy Constructor

export class Post {
  title:string;
  content:string;
  img:string;

  // Copy constructor.
  constructor(obj: Object) {
    this.title = obj['title'];
    this.content = obj['content'];
    this.img = obj['img'] || 'test';
  }

  // New static method.
  static fromJSONArray(array: Array<Object>): Post[] {
    return array.map(obj => new Post(obj);
  }
}

If you're using an editor that supports code completion, you can change the type of the obj and array parameters to Post:

export class Post {
  title:string;
  content:string;
  img:string;

  // Copy constructor.
  constructor(obj: Post) {
    this.title = obj.title;
    this.content = obj.content;
    this.img = obj.img || 'test';
  }

  // New static method.
  static fromJSONArray(array: Array<Post>): Post[] {
    return array.map(obj => new Post(obj);
  }
}