Angular 2 pipe, using observable correctly, my pipe does not return a poster path

Mikkel picture Mikkel · Oct 29, 2016 · Viewed 13.3k times · Source

I'm trying to call my service to get a poster Url for all my movies (Want to show the poster of them). I'm using Angular2 and have for now created a pipe that should do the job.

I have this code:

<div class="row small-up-1 medium-up-2 large-up-4">
    <div class="column" *ngFor="let movie of MoviesOnNas">
        <span>{{movie.MovieYear}}</span>
        <img src="{{movie.MovieId | poster}}" class="thumbnail" alt="">
        {{movie.MovieTitle}}
    </div>
</div>

Here you see the let movie of MoviesOnNas , it will show all movies there is in the MoviesOnNas object.

In the line:

<img src="{{movie.MovieId | poster}}" class="thumbnail" alt="">

I'm trying to use a custom pipe I have created. It looks like this.

@Pipe({ name: 'poster' })
export class PosterPipe implements PipeTransform {

constructor(public movieService: MovieService) {

}

transform(value: string, args: string[]): any {
    if (value) {
        // Go call api to get poster.
        this.movieService.getMoviePoster(value).subscribe((data) => {
            console.log("http://image.tmdb.org/t/p/w500" + data);
            var poster = "http://image.tmdb.org/t/p/w500" + data;
            return poster;
        });
    }
    else {
        // Insert could not find movie poster.
        return "../../assets/img/poster.png";
    }
}
}

The pipe should return the poster url. The problem is that The code I have provided does not work. It won't load the url and show the picture. In the console.log, I can see that the url path is actually working if I use it in the browser.

If I do something like this:

if (value) {

    return "http://image.tmdb.org/t/p/w500/bqLlWZJdhrS0knfEJRkquW7L8z2.jpg"
} 

Then it shows the picture correctly. So the problem must be the observable subscribe?

Can any see what could be wrong here?

Answer

Bazinga picture Bazinga · Oct 30, 2016

You should use the async pipe when dealing with async operations. Remember to return a promise or an observable.

@Pipe({
  name: 'poster'
})
class PosterPipe {
  apiCall;
  constructor() {
    // simulate http call
    this.apiCall = Observable.create(observer => {
      observer.next("http://lorempixel.com/400/200/sports/");
    });
  }

  transform(value: string) {
    if(value) {
      return this.apiCall.first();
    }

    return Observable.of("../../assets/img/poster.png");


  }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <img src="{{MovieId | poster | async}}">
    </div>
  `,
})
export class App {
   MovieId:string;
   constructor() {
    this.MovieId = 'Exists'
   }
}

Working Plunker