みなさんこんにちは、現役エンジニアのサメハックです
未経験から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を更新しているよ!
更新されるたびに、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フォローしてもらえると嬉しいです🦈