2017-09-27 69 views
1

我開始使用Angular 2中的Observable,並且我無法弄清楚如何在我的視圖中正確使用它們。Angular 2 - 在視圖中操作rxjs Observable

我正在使用Angular 2與角度縮放,並使用@select()修飾器從redux商店中檢索我的selectedMovie$。這部分工作正常,組件基本上分派一個redux事件來設置初始化時的默認selectedMovie$。 redux商店正確更新,但當我試圖在視圖中完善它時,我遇到了一些問題。

import { Component, OnInit } from '@angular/core'; 
import { NgRedux, select } from '@angular-redux/store'; 
import { MovieActions} from '../store/app.actions'; 
import { IAppState} from '../store/reducers'; 
import { MovieService } from '../movie.service'; 
import { Observable } from 'rxjs/Observable'; 
import { IMovie } from '../movie.model'; 

@Component({ 
    selector: 'app-movies-container', 
    templateUrl: './movies-container.component.html', 
    styleUrls: ['./movies-container.component.css'], 
    providers: [MovieService] 
}) 
export class MoviesContainerComponent implements OnInit { 
    movies: Array<IMovie>; 
    @select() readonly selectedMovie$: Observable<IMovie>; // HERE - Get data from the redux store 

    constructor(
    private movieService: MovieService, 
    private movieActions: MovieActions, 
    private ngRedux: NgRedux<IAppState> 
) { } 

    ngOnInit() { 
    // Fetch movies and use the first one as default displayed movie. 
    this.getMovies() // HERE - Takes the first movie and make it the default selectedMovie by dispatching a redux action 
     .then(movies => 
     this.ngRedux.dispatch(this.movieActions.changeSelectedMovie(this.movies[0])) 
    ); 
    } 

    getMovies() { // HERE: Call an API, returns an array of movies in data.results 
    return this.movieService.getMostPopular() 
     .then(data => this.movies = data.results); 
    } 

    onSelect(movie: IMovie) { 
    this.ngRedux.dispatch(this.movieActions.changeSelectedMovie(movie)); 
    } 
} 

這裏談到的觀點:

<div *ngIf="movies"> 
    <md-list> 
    <h3 md-subheader>Most popular movies NOW!</h3> 
    <pre> 
     {{(selectedMovie$ | async | json).id}} // This fails and displays nothing. I'd expect it to display the movie id 
    </pre> 
    <md-list-item 
     *ngFor="let movie of movies" 
     [class.selected]="movie.id === (selectedMovie$ | async | json).id" // This is a real deal, I don't know what's the syntax to use. I wanted to compare ids 
     (click)="onSelect(movie)" 
    > 
     <img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" /> 
     {{movie.title}} 
    </md-list-item> 
    </md-list> 

    <app-movie-card [movie]="selectedMovie$ | async | json"></app-movie-card> // This component gets the object correctly formatted 
</div> 

也許我只是沒有使用正確的語法。或者,也許我不應該在視圖中首先使用Observer?


編輯:溶液

<div *ngIf="movies && (selectedMovie$ | async); let selectedMovie"> 
    <md-list> 
    <h3 md-subheader>Most popular movies NOW!</h3> 
    <md-list-item 
     *ngFor="let movie of movies" 
     [class.selected]="movie.id === selectedMovie.id" 
     (click)="onSelect(movie)" 
    > 
     <img src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" /> 
     {{movie.title}} 
    </md-list-item> 
    </md-list> 

    <app-movie-card [movie]="selectedMovie"></app-movie-card> 
</div> 

回答

3

問題從一個共同的誤解,JSON是用於普通目的的同義詞結果。 這不是

json管道將輸入轉換成實際的JSON字符串。因此(selectedMovie$ | async | json)表達式計算爲一個字符串,並且沒有id屬性。

使用AoT編譯會很有幫助,因爲它允許檢測模板中的類型問題,並且在這種情況下可能會導致類型錯誤。

應該是(selectedMovie$ | async).id

如果多次使用(selectedMovie$ | async)(如本例中),則會導致多次訂閱。它可以通過將其分配到局部變量進行優化,如解釋here

<div *ngIf="movies"> 
    <ng-container *ngIf="(selectedMovie$ | async); let selectedMovie"> 
    ... 
    {{selectedMovie.id}} 
    ... 
    </ng-container> 
</div> 
+0

非常聰明的把戲。對於在同一模板中存儲值以供稍後使用非常有用。使用''而不是div的任何特別的興趣? – Vadorequest

+1

查看https://stackoverflow.com/questions/39547858/angular-2-ng-container。 Tl; DR:它不污染布局。 – estus