0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Stimulus】他のコントローラーを直接呼び出す

Posted at

Stimulusには他のコントローラーを取得し、そのコントローラーの関数を実行することができます。これまで使ったことのない機能だったのでどういう状況で使えそうか試してみた。

責務の分離例

基本的には責務を分離しているときに使えそうです。逆にいうと分離せず、同じコントローラーで書くこともできますが、結果的に責務が分離されず肥大しているコントローラーはよくあるので、それを防ぐことができそうです。

例えばTimerControllerというタイマーを扱うコントローラーとBoardControllerというゲームのボードを扱うコントローラーがあるとします。
下の処理では、ゲームを開始したときに、タイマーを自動で始動させるようにしています。TimerController#startBoardControllerに実装することもできますが、ボードとタイマーのそれぞれの役割を分離しています。

// app/javascript/controllers/timer_controller.js
import { Controller } from "@hotwired/stimulus"

export default class TimerController extends Controller {
  // existing code ...

  start() {
    if (this.isRunning) return;

    this.isRunning = true;
    this.intervalId = setInterval(() => {
      this.totalSeconds++;
      this.updateDisplay();
    }, 1000);

    this.updateButtonStates();
  }

  // existing code ...
}
// app/javascript/controllers/board_controller.js
import { Controller } from "@hotwired/stimulus"

export default class BoardController extends Controller {
  static targets = ["timer"]

  // existing code ...

  processNumberInput(value) {
    this.startTimer();

    // existing code ...
  }

  startTimer() {
    const timerController = this.application.getControllerForElementAndIdentifier(this.timerTarget, "timer")
    timerController.start();
  }
}

共通化例

Formのリクエスト方法の検討」をしたときに、Ghost Form パターンがありました。Ghost From、いわゆる画面に表示させないが、非表示のエレメントをStimulusからリクエストするというものでした。
詳しくは『サーバ側だけでフォーム画面をインタラクティブに! 〜Hotwire を活用した「Ghost Formパターン」〜

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="ghost-form"
export default class extends Controller {
  static targets = [ "originalForm", "ghostForm" ]

  submit(event) {
    const formData = new FormData(this.originalFormTarget)
    formData.delete("_method")
    formData.delete("authenticity_token")

    for (const [key, value] of formData.entries()) {
      const ghost_key = "ghost_" + key
      const input = this.ghostFormTarget.querySelector(`input[name="${ghost_key}"]`)
      if (input) {
        input.value = value;
      }
    }
    this.ghostFormTarget.requestSubmit()
  }
}

*『サーバ側だけでフォーム画面をインタラクティブに! 〜Hotwire を活用した「Ghost Formパターン」〜』より引用

このような実装例になっており、Ghost Form パターンを利用するケースではどこでも共通化できるようになっています。

こういった場合でも、ghost_form_controllerを他のコントローラーから参照するようにすれば、共通化ができそうです。

// app/javascript/controllers/board_controller.js
import { Controller } from "@hotwired/stimulus"

export default class BoardController extends Controller {
  static targets = ["timer", "ghostForm"]

  // existing code ...

  processNumberInput(value) {
    this.startTimerIfExists();

    // existing code ...

    this.submitGhostForm();
  }

  startTimer() {
    const timerController = this.application.getControllerForElementAndIdentifier(this.timerTarget, "timer")
    timerController.start();
  }

  submitGhostForm() {
    const ghostFormController = this.application.getControllerForElementAndIdentifier(this.ghostFormTarget, "ghost_form")
    ghostFormController.submit();
  }
}

まとめ

責務を分離することを主とした例と共通化することを主とした例をそれぞれ見てきました。責務の分離、共通化することで、コントローラーの肥大化を防ぎ、メンテナンス性の向上が期待できそうです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?