【Angular】別のコンポーネントのsliderと画像のサイズを連動させよう!

ANGULAR

みなさんこんにちは、現役エンジニアのサメハックです

未経験からWebエンジニアに転職し、
正社員として5年働いたのちフリーランスとして独立しました。

Angularの解説シリーズです。

今回は別のコンポーネントのsliderと画像のサイズを連動させる方法について学んでいきましょう!

駆け出しエンジニアや未経験の方、
また新入社員を指導する先輩社員にとっても
わかりやすいように解説していきます!

この記事を読むと・・・
  • BehaviorSubjectの使い方がわかる

※PCにnpm、nodeがインストールされている前提で記述します。
 yarn等をお使いの方は読み替えてください。

環境がない人はcodesansbox等を使ってね!

作りたいもの

今回は別のコンポーネントであるスライダーの値と画像のサイズが
連動したアプリケーションを作ります。

これが今回の完成形だよ!

実現のためにすべきこと

  • BehaviorSubjectを使って画像サイズの値を管理
  • スライダー操作で保管した値を更新
  • 画像コンポーネントで画像サイズの値を購読し、変更されるたびにCSS更新関数実行

この3つを設定することで、
異なるコンポーネントでも同一の値を参照することができます。

BehaviorSubjectについて

値を保管する構文

import { BehaviorSubject } from 'rxjs';

// BehaviorSubjectの宣言
データ保管用変数 = new BehaviorSubject<型>(初期値);

保管した値を更新する構文

データ保管用変数.next(更新したい値);

保管した値を購読する

// 購読設定停止用
private subscriptions = new Subscription();

ngOnInit(): void {
  this.subscriptions.add(
    // データ保管用変数を購読する
    // ※データ保管用変数が更新される度に呼ばれる
    データ保管用変数.subscribe(
      (response) =>
        // 任意の処理を実行
    )
  );
}
BehaviorSubjectについて詳しく知りたい方は
こちらの記事を参考にしてね!

【Angular】BehaviorSubjectを使って状態管理しよう!【サンプルコードあり】

実行環境

Angularのバージョンが古いと動かないことがあるよ!
うまく動かなければアップデートしてね!

実際に作ってみよう!

ファイル作成

ng new my-app
cd my-app
ng generate component slider
ng generate component image
ng generate service service/image-size
npm start

モジュールファイルの設定

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { SliderComponent } from './slider/slider.component';
import { ImageComponent } from './image/image.component';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [AppComponent, SliderComponent, ImageComponent],
  imports: [BrowserModule, FormsModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

サービスファイルの設定

image-size.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ImageSizeService {
  // スライダー初期値
  slider = {
    value: 250,
  };

  // 画像サイズ
  imageSize$ = new BehaviorSubject(250);

  constructor() {}

  // 画像サイズの更新
  update(size: number) {
    this.imageSize$.next(size);
  }
}
``` 


このファイルの値をコンポーネントから更新・参照するよ!

スライダー用コンポーネント

slider.component.html

<p>slider works!</p>

<!-- テキスト -->
<p>
  <span id="txt">{{ service.slider.value }}</span
  >px
</p>

<!-- スライダー -->
<input
  type="range"
  id="slider"
  min="10"
  max="500"
  value="service.slider.value"
  [(ngModel)]="service.slider.value"
  (ngModelChange)="service.update(service.slider.value)"
/>

slider.component.ts

import { Component } from '@angular/core';
import { ImageSizeService } from '../service/image-size.service';

@Component({
  selector: 'app-slider',
  templateUrl: './slider.component.html',
  styleUrls: ['./slider.component.scss'],
})
export class SliderComponent {
  // HTMLから直接参照したいのでpublicとすること
  constructor(public service: ImageSizeService) {}
}
HTMLからDIしたファイルへアクセスしたい場合はpublicとするのがポイントだよ!

画像表示コンポーネント

image.compoent.html

<p>image works!</p>
<!-- 画像 -->
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>
<img
  class="my-image"
  src="https://samehack.com/wp-content/uploads/2021/09/sameHackIcon.png"
  id="img"
  alt=""
/>

image.compoent.ts

import { Component } from '@angular/core';
import { Subscription } from 'rxjs';
import { ImageSizeService } from '../service/image-size.service';

@Component({
  selector: 'app-image',
  templateUrl: './image.component.html',
  styleUrls: ['./image.component.scss'],
})
export class ImageComponent {
  constructor(private service: ImageSizeService) {}

  // 購読設定停止用
  private subscriptions = new Subscription();

  ngOnInit() {
    this.subscriptions.add(
      this.service.imageSize$.subscribe((res) => {
        // serviceファイルのimageSize$を購読し、
        // 更新されるとresizeを実行
        this.resize(res);
      })
    );
  }

  ngOnDestroy() {
    // 購読の停止
    this.subscriptions.unsubscribe();
  }

  resize(size: number) {
    // クラス名がmy-imageの要素を取得し、HTMLCollectionOfにキャストする
    const list = Array.from(
      document.getElementsByClassName(
        'my-image'
      ) as HTMLCollectionOf
    );

    // 取得した要素の高さ・幅を設定
    list.forEach((element) => {
      element.style.height = size + 'px';
      element.style.width = size + 'px';
    });
  }
}
serviceファイルのimageSize$を購読して、
更新されるたびに、CSSを更新しているよ!

これで同じものができたと思います。

GitHubのサンプルコード

今回作ったものはGitHubにあげているので
使いたい人は是非ダウンロードしてみてください。

GitHub - same-hack/Angular-BehaviorSubject-slider-img-size
Contribute to same-hack/Angular-BehaviorSubject-slider-img-size development by creating an account on GitHub.

ちなみに、同じようなものをHTML/CSSとJavaScriptのみで作成した記事もあるので
そちらも参考にしてみてください

【JavaScript】スライダーの値と画像サイズを連動させよう!【HTML/CSS】

まとめ

  • 共通の値を複数のコンポーネントから更新・参照するにはBehaviorSubjectを使う

満足いただけたら、1クリックなのでSNSフォローしてもらえると嬉しいです🦈

タイトルとURLをコピーしました