Angular でfetch したURL をswiper で利用する

はじめに

以前、angular でhtmlにベタ書きした画像URLをslide として表示する方法をこちらの記事でまとめました。
この時気づいていませんでしたが、API から画像のURL をfetch して表示する際に少しハマったことがあったのでその対応をまとめています。

nananao-dev.hatenablog.com

Angular でfetch したURL をswiper で利用する

画像のURL をfetch する際に多少の遅延が生じることになりますが、その遅延に起因してslide の切替わり時に一部の画像が表示されません。

どちらかというとAngular というよりはswiper 側でなんとかして欲しいところですが、今回はAngular 側でwalk-around を行いました。

swiper でslide 切替わり時に画像が表示できない

ダミーコードを書きました。
以下のように1秒遅延して画像のURL を返すサービスを書きました。

fetch(): Observable<string> {
  return of('https://source.unsplash.com/random/512x512?portrait').pipe(
    // これをコメントアウトすると期待通り表示される
    delay(1000)
  );
}

Component でsubscribe します。

ngOnInit() {
  this.swiperService.fetch().subscribe(
    (response: string) => {
      this.image = response;
    }
  );
}

HTML側で読み込みます。

<div class="swiper-container">
  <div class="swiper-wrapper">

    <div class="swiper-slide">
      <img src="{{ image }}">
    </div>
    <div class="swiper-slide">
      <img src="{{ image }}">
    </div>

  </div>
  <div class="swiper-pagination"></div>
  <div class="swiper-button-next"></div>
  <div class="swiper-button-prev"></div>
</div>

動きそうな匂いはします。
が、なぜか以下のように imgタグ のsrc が消失しているslide が1つあります。
この子はswiper のoption として loop: true を利用してslide をloop している際の 最後のスライドから最初のスライドへ戻る 際のタグです。

<div class="swiper-slide swiper-slide-duplicate swiper-slide-active">
  <img>
</div>

そもそも swiper-slide-duplicateswiper-slide-active のclass はなんやねん。という方は公式ドキュメントの loop の欄をご覧ください。

swiperjs.com

stackblitz はこちらです。
2枚のslide を利用していますが、2枚目から1枚目への遷移する際に画像が表示されていません。
また delay(1000)コメントアウトすると問題なく表示できることが確認できると思います。

stackblitz.com

changeDetectorRef.detectChanges で強制的に再描画させる

Angular の問題には思えませんがAngular 側でWalk-around してみます。
なにをしたかというと、データが取得できてから再び changeDetectorRef.detectChanges で再描画しました。
豪腕ですね。スマートではないです。

ngOnInit() {
  const a = this.swiperService.fetch().subscribe(
    (response: string) => {
      this.image = response;
      // 強制的に再描画する
      this.changeDetectorRef.detectChanges();
      // Optionを読み込む
      const nativeElement = this.elementRef.nativeElement;
      this.swiper = new Swiper(nativeElement.children[0], this.swipeOptions);
    }
  );
}

stackblitz はこちらです。
全ての画像が表示できていますね。

stackblitz.com

まとめ

Angular でfetch したURL をswiper で利用する方法をまとめました。
2日くらい潰してしまった。。。

勇気を出して本家にissue を書いてみました。
作者のサムネが怖くてビビってます。

github.com