@Input()未定义,即使它是

时间:2018-04-17 18:28:32

标签: angular typescript

我目前正在开展一个展示电影信息的项目。使用@Input(),我将电影细节从父组件(电影)绑定到子组件(电影细节)。

父组件(电影)

import { Component, OnInit } from '@angular/core';
import { IMovie } from './movie';
import { MoviesService } from './movies.service';
import { IPopular } from './popular';
import { HttpClient } from '@angular/common/http';
import { MovieDetailComponent } from '../movie-detail/movie-detail.component';

@Component({
  selector: 'app-movies',
  templateUrl: './movies.component.html',
  styleUrls: ['./movies.component.css']
})
export class MoviesComponent implements OnInit {
  moviesList: IPopular[] = [];
  movie: IMovie;
  selectedMovie: IMovie;

  constructor(private _moviesService: MoviesService) { }

  ngOnInit() {
    this._moviesService.getPopularMovies()
      .subscribe(moviesList => {
        this.moviesList = moviesList;
      },
        error => console.log(error)
      );

  }

  onSelect(movie: IMovie): void {
    this.selectedMovie = movie;
    window.setTimeout(function() {window.scrollTo(0, 5000); }, 300);
  }
}

父HTML

<div>
  <ul class="movies" *ngFor="let movie of moviesList.results">
    <li [class.selected]="movie === selectedMovie" (click)="onSelect(movie)">
      <img class="poster" [src]="'https://image.tmdb.org/t/p/w200/'+ movie.poster_path">
      <br> {{movie.title}} 
    </li> 
  </ul>
</div>

<app-movie-detail [movie]='selectedMovie'></app-movie-detail>

iMovie中

export interface IMovie {
    vote_count: number;
    id: number;
    video: boolean;
    vote_average: number;
    title: string;
    popularity: number;
    poster_path: string;
    original_language: string;
    original_title: string;
    genre_ids: number[];
    backdrop_path: string;
    adult: boolean;
    overview: string;
    release_date: string;
}

IPopular

 import { IMovie } from './movie';

export interface IPopular {
    results: Array<IMovie>;
    page: number;
    total_results: number;
    dates: DateTimeFormat;
    total_pages: number;
}

子组件

import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { IResult } from './result';
import { IVideo } from './video';
import { IMovie } from '../movies/movie';
import { MovieDetailService } from './movie-detail.service';
@Component({
  selector: 'app-movie-detail',
  templateUrl: './movie-detail.component.html',
  styleUrls: ['./movie-detail.component.css']
})
export class MovieDetailComponent implements OnChanges {

  @Input() movie: IMovie;

  videoList: IVideo[] = [];
  video: IResult;

  constructor(private _moviedetailService: MovieDetailService) { }

  ngOnChanges() {
    this._moviedetailService.getTrailer(this.movie.id)
      .subscribe(videoList => {
        this.videoList = videoList;
      },
        error => console.log(error)
      );
  }

  ScrollToTop(): void {
    window.setTimeout(function() {window.scrollTo(5000, 0); }, 300);
  }
}

儿童HTML

<body class="background" [background]="'https://image.tmdb.org/t/p/original'+ movie.backdrop_path" *ngIf="movie">
  <div class="detailpage">
    <h1>{{ movie.title }}</h1>
    <div>
      <img class="poster" [src]="'https://image.tmdb.org/t/p/w300/'+ movie.poster_path">
      <div class="movieinfo">
        <h2>Overview:</h2>
        <p>{{ movie.overview }}</p>
        <h3>Rating:</h3>
        <p>{{ movie.vote_average}} / 10</p>
        <h3>Release Date:</h3>
        <p>{{movie.release_date}}</p>
      </div>
      <div class="trailer" *ngFor="let videos of videoList.video">
        <iframe [src]="'https://www.youtube.com/watch?v=' + videos.key"></iframe>
      </div>
    </div>
    <span class="top" (click)="ScrollToTop()">Back to top</span>
  </div>
</body>

IVideo

import { IResult } from './result';

export interface IVideo {
  id: number;
  results: Array<IResult>;
}

IResult

export interface IResult {
    id: string;
    iso_639_1: string;
    iso_3166_1: string;
    key: string;
    name: string;
    site: string;
    size: number;
    type: string;
}

使用此代码,我收到ERROR TypeError:无法读取未定义的属性'id'

ERROR TypeError: Cannot read property 'id' of undefined
    at MovieDetailComponent.ngOnChanges (movie-detail.component.ts:22)
    at checkAndUpdateDirectiveInline (core.js:12365)
    at checkAndUpdateNodeInline (core.js:13893)
    at checkAndUpdateNode (core.js:13836)
    at debugCheckAndUpdateNode (core.js:14729)
    at debugCheckDirectivesFn (core.js:14670)
    at Object.eval [as updateDirectives] (SearchresultComponent.html:10)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:14655)
    at checkAndUpdateView (core.js:13802)
    at callViewAction (core.js:14153)

你们有什么建议来解决这个问题?

3 个答案:

答案 0 :(得分:0)

很可能是因为您的selectedMovieundefined,直到您点击其中一个。你可以解决它隐藏你的电影细节组件,如果没有选择一个:

<app-movie-detail *ngIf="selectedMovie" [movie]="selectedMovie"></app-movie-detail>

答案 1 :(得分:0)

  

Angular(重新)设置数据绑定输入属性时的响应。该方法接收当前和先前属性值的SimpleChanges对象。   在ngOnInit()之前以及每当一个或多个数据绑定输入属性发生更改时调用。

将您的代码包装到条件检查中:crawl = crawl->getNode(key[i]);

if(this.movie) {...}
当输入属性发生变化时,将再次调用

ngOnChanges() { if(this.movie) { console.log(this.movie.id) } }

答案 2 :(得分:0)

启动子组件时this.movie信息不可用。根据您的逻辑电影,仅在父组件中选择电影时才能使用详细信息。因此未定义的错误。

只有在电影详细信息可用时才应在ngOnChanges中进行服务呼叫。尝试从子组件中更新ngOnChanges,如下所示

ngOnChanges() {
if (this.movie) {
 this._moviedetailService.getTrailer(this.movie.id)
  .subscribe(videoList => {
    this.videoList = videoList;
  },
    error => console.log(error)
  );
}

}