Angular 6字符串插值在.subscribe()内部的值不更新

5

我有一个组件,用于显示特定视频的标题和艺术家。当我在我的服务中调用 playNext() 时,它应该使用新数据更新标题和艺术家。我进行了 console.log 并验证了订阅有效。每次调用 playNext() 时,我都能获得更新后的值,但是模板中的值没有被更新。它只在第一次正确显示。我漏掉了什么吗?

这是我的组件代码:

@Component({
  selector: 'ntv-now-playing',
  templateUrl: './now-playing.component.html',
  styleUrls: ['./now-playing.component.css']
})
export class NowPlayingComponent implements OnInit {
  nowPlaying: Observable<Video>;
  video: Video;
  constructor(private videoService: VideoPlayerService) { }

  ngOnInit() {
    this.nowPlaying = this.videoService.getNowPlaying();
    console.log('nowPlayingComponent');
    this.nowPlaying.subscribe(v => {
      this.video = v;
      console.log('nowPlaying:', this.video);
    });
  }
}

在我的服务中,我这样做:为了简洁起见,我删除了一些工作代码。
@Injectable()
export class VideoPlayerService {
  ...
  nowPlayingChanged = new Subject<Video>();
  ...
  private nowPlaying: Video;

  constructor(private db: AngularFirestore) {}
  ...

  getNowPlaying(): Observable<Video> {
    return this.nowPlayingChanged;
  }

  playNext(vIdx: number, lastIdx: number) {
    console.log('playNext()');
    this.nowPlaying = this.videos[vIdx];
    console.log(this.nowPlaying);
    this.nowPlayingChanged.next(this.nowPlaying);

  }
}

我的模板中包含以下内容:

<div class="video-info">
  <h5>{{video?.title}} - {{video?.artist}}</h5>
  <div>Channel Info&nbsp;&nbsp;<button class="btn btn-secondary">+ Subscribe</button></div>
</div>

每次调用 playNext() 函数时,组件内的 subscribe 函数都会在控制台输出这个信息,所以我知道它是正确变化的,只是用户界面没有更新。

nowPlaying: {artist: "Alan Walker", duration: "3:32", startTime: Timestamp, thumbnailPath: "https://i.ytimg.com/vi/60ItHLz5WEA/hqdefault.jpg", title: "Faded"}
nowPlaying: {artist: "Deadmau5", duration: "3:37", thumbnailPath: "https://i.ytimg.com/vi/UG3sfZKtCQI/hqdefault.jpg", title: "Monophobia", videoId: "UG3sfZKtCQI"}
nowPlaying: {artist: "Steve Aoki", duration: "59:55", thumbnailPath: "https://i.ytimg.com/vi/sR3w1P2nPH8/hqdefault.jpg", title: "Tomorrowland", videoId: "x9ZkC3OgI78"}
video-player.component.ts:69 

非常感谢您的咨询。我看到有些人使用ngZone,但我听说这可能不是最好的方法,老实说,它感觉有点hacky。


一切看起来对我来说都很好。你可以尝试一件事情,在具有video-info类的父div中尝试附加*ngIf="video",我知道你有一个?,它是一个替代品,但你仍然可以尝试一下,然后在你的父div中再创建一个div,用json {{ video | json }}显示视频。 - Immad Hamid
1
NgZone.isInAngularZone() 应该会给你答案。 - yurzui
1个回答

12

可能这会有所帮助:

@Component({
  selector: 'ntv-now-playing',
  templateUrl: './now-playing.component.html',
  styleUrls: ['./now-playing.component.css']
})
export class NowPlayingComponent implements OnInit {
  nowPlaying: Observable<Video>;
  video: Video;
  constructor(
    private videoService: VideoPlayerService,
    private changeDetector: ChangeDetectorRef
   ) { }

  ngOnInit() {
    this.nowPlaying = this.videoService.getNowPlaying();
    console.log('nowPlayingComponent');
    this.nowPlaying.subscribe(v => {
      this.video = v;
      this.changeDetector.detectChanges();
      console.log('nowPlaying:', this.video);
    });
  }
}

谢谢@Maksym。这解决了问题。我现在正在阅读ChangeDetectorRef文档。我一直以为Angular会自动处理这个问题。但如果数据是异步的,似乎并不是这样。很抱歉我还不能点赞..需要再多一些声望。 - Noel R.
1
@NoelR. 我还注意到一件事 - 在你的服务中,nowPlayingChanged 是一个 Subject,但在 getNowPlaying 中你只是简单地返回它。尝试 return this.nowPlayingChanged.asObservable(),起初这不会让你在服务外部执行 .next(),所以你的组件将始终与服务数据同步,并且当它转换为组件的 Observable 时,它可能有助于检测原始 Subject 中的更改。只是一个猜测,但仍然可能有帮助。 - Maksym Shevchenko
我记得之前尝试过那个选项,但仍然没有检测到变化。如果我第一次尝试时错过了什么,我可以再试一次。谢谢跟进。 - Noel R.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接