刺激のためのベストプラクティス


Hotwire、ターボフレームとターボストリームでいくつかの生産アプリケーションを構築私の経験から、インタラクティブなWebアプリケーションを構築するために必要なもののバルクを処理します.
しかし、確かに少しJavaScriptの刺激から振りかける必要があります.
私はHappiに含まれるすべての刺激コントローラを走らせたいです、そして、私がこれまでに学んだものから若干の「最高の習慣」について話します.

あなたが書く最初のコントローラ
私はこれまで構築したすべてのHotwireアプリでは、私が必要となる最初のコントローラは、togglecontrollerです.通常、私はTailwind UIレイアウトをセットアップして、Navメニューを隠して、示し始める必要があるときです.

切り替え
あなたが下に見るように、私はstimulus-useからuseclickexternalを輸入しています、それは小さい、構成可能なヘルパーとの大きなライブラリです、私はあなたにそれをチェックするように強く勧めます!
私がここでするのが好きであるもう一つのものは若干の使用コメントを残しています、それはコントローラにのぞき見するのをより簡単にして、どのように働くか、そして、どんなデータ属性が私のHTMLに加える必要があるかについて見ます.
import { Controller } from "@hotwired/stimulus";
import { useClickOutside } from "stimulus-use";

/*
 * Usage
 * =====
 *
 * add data-controller="toggle" to common ancestor
 *
 * Action (add this to your button):
 * data-action="toggle#toggle"
 *
 * Targets (add this to the item to be shown/hidden):
 * data-toggle-target="toggleable" data-css-class="class-to-toggle"
 *
 */
export default class extends Controller {
  static targets = ["toggleable"];

  connect() {
    // Any clicks outside the controller’s element can 
    // be setup to either add a 'hidden' class or 
    // remove a 'open' class etc.
    useClickOutside(this);
  }

  toggle(e) {
    e.preventDefault();

    this.toggleableTargets.forEach((target) => {
      target.classList.toggle(target.dataset.cssClass);
    });
  }

  clickOutside(event) {
    if (this.data.get("clickOutside") === "add") {
      this.toggleableTargets.forEach((target) => {
        target.classList.add(target.dataset.cssClass);
      });
    } else if (this.data.get("clickOutside") === "remove") {
      this.toggleableTargets.forEach((target) => {
        target.classList.remove(target.dataset.cssClass);
      });
    }
  }
}
私が強調することができる最大のことは、あなたのコントローラをできるだけ一般的にすることです.私はこのコントローラNavbarControllerをして、それからNavbarをトグルするだけであることができました.これは一般的なので、私はそれのために私のアプリで何度も達しているし、それを再利用することができました.

オートコントローラー
import { Controller } from "@hotwired/stimulus";
import Rails from "@rails/ujs";

/*
 * Usage
 * =====
 *
 * add data-controller="auto-submit" to your <form> element
 *
 * Action (add this to a <select> field):
 * data-action="change->auto-submit#submit"
 *
 */
export default class extends Controller {
  submit() {
    Rails.fire(this.element, "submit");
  }
}
これは小さいです、私は自動的にこれらのドロップダウンが変更されたときにフォームを提出するために必要な、先に行くと変更を保存します.再び、私はそれが一般的なので、同様の動作を必要とする他の場所で再利用することができます続けた.


コントローラ

これはスーパー便利です、それは空の状態が適切にターボストリームで動作することができます.それがなければ、ターボストリームは、画面上に新しいメッセージをプッシュすると、UIは';まだメッセージを持っていない';表示され、すべてが壊れて見えます.
また、stimulus-useのusumutationフックに依存します.そして、それはターボストリームでちょうどworkstmを意味します、そして、我々はどんな複雑なコールバックも必要としません、そして、それでも、カスタムActionCableメッセージに達する必要はありません.
import { Controller } from "@hotwired/stimulus";
import { useMutation } from "stimulus-use";

/*
 * Usage
 * =====
 *
 * add data-controller="display-empty" to common ancestor
 *
 * Classes:
 * data-display-empty-hide-class="hidden"
 *
 * Targets:
 * data-display-empty-target="emptyMessage"
 * data-display-empty-target="list"
 *
 */
export default class extends Controller {
  static targets = ["list", "emptyMessage"];
  static classes = ["hide"];

  connect() {
    useMutation(this, {
      element: this.listTarget,
      childList: true,
    });
  }

  mutate(entries) {
    for (const mutation of entries) {
      if (mutation.type === "childList") {
        if (this.listTarget.children.length > 0) {
          // hide empty state
          this.emptyMessageTarget.classList.add(this.hideClass);
        } else {
          // show empty state
          this.emptyMessageTarget.classList.remove(this.hideClass);
        }
      }
    }
  }
}

フラッシュコントローラ
これは私が好きなように一般的ではない、多分私は呼び出す必要がありますautohidecontroller?これはかなり簡単ですが、自動的に3秒後に非表示になりますが、また、' X 'をクリックして却下することができます.
import { Controller } from "@hotwired/stimulus";

/*
 * Usage
 * =====
 *
 * add data-controller="flash" to flash container
 * p.s. you probably also want data-turbo-cache="false"
 *
 * Action (for close cross):
 * data-action="click->flash#dismiss"
 *
 */
export default class extends Controller {
  connect() {
    setTimeout(() => {
      this.hideAlert();
    }, 3000);
  }

  dismiss(event) {
    event.preventDefault();
    event.stopPropagation();

    this.hideAlert();
  }

  hideAlert() {
    this.element.style.display = "none";
  }
}

ホバーカルコントローラ
この1つのホバーカードでは、TwitterやGithubのユーザーアバターをホバリングに似ています.私はもともとBoring Railsからこのコードを得た、それはすべての物事のための素晴らしいリソース/刺激/hotwire、あなたは間違いなくそれをチェックアウトする必要があります!
注:あなたはそれをより設定可能にし、隠しクラスのStimulus CSS classesを使用して、これを使用して、ボーナスポイントを計画している場合.
また、フェッチを直接使用するのではなく、新しいRails Request.jsライブラリを使うのも賢いかもしれません.
import { Controller } from "@hotwired/stimulus";

/*
 * Usage
 * =====
 *
 * add the following to the hoverable area
 * data-controller="hovercard"
 * data-hovercard-url-value="some-url" # Also make sure to `render layout: false`
 * data-action="mouseenter->hovercard#show mouseleave->hovercard#hide"
 *
 * Targets (add to your hovercard that gets loaded in):
 * data-hovercard-target="card"
 *
 */
export default class extends Controller {
  static targets = ["card"];
  static values = { url: String };

  show() {
    if (this.hasCardTarget) {
      this.cardTarget.classList.remove("hidden");
    } else {
      fetch(this.urlValue)
        .then((r) => r.text())
        .then((html) => {
          const fragment = document
            .createRange()
            .createContextualFragment(html);

          this.element.appendChild(fragment);
        });
    }
  }

  hide() {
    if (this.hasCardTarget) {
      this.cardTarget.classList.add("hidden");
    }
  }

  disconnect() {
    if (this.hasCardTarget) {
      this.cardTarget.remove();
    }
  }
}

MessageComposerController
このコントローラは本当に私はこれまで書かれている唯一のアプリケーションの特定の刺激コントローラは、これはかなり顕著な、私は完全な生産品質のアプリを構築したことを考慮し、JSのラインのほんの一握りで、これは本当にHotwireとターボの力を示しています.
Happiは、一般的なメッセージを書く自動化に役立つ応答を缶詰にしています.缶詰の応答をクリックすると、これはHTMLを受け取り、アクションテキストtrixエディタにプッシュします.
import { Controller } from "@hotwired/stimulus";

/*
 * Usage
 * =====
 *
 * add this to the messages form:
 * data-controller="message-composer"
 *
 * Action (add this to your snippets):
 * data-action="click->message-composer#snippet" data-html="content..."
 *
 */
export default class extends Controller {
  connect() {
    this.editor = this.element.querySelector("trix-editor").editor;
  }

  snippet(event) {
    this.editor.setSelectedRange([0, 0]);
    this.editor.insertHTML(event.target.dataset.html);
  }
}

NavigationSelectController
ここで別の簡単な1つは、選択メニューを介して携帯電話上で応答性のナビゲーションに使用されます.
これは設定画面の中で、大きな画面上で使用され、我々は側面を下にし、ドロップダウンにこれらのサブページに設定内の移動をドロップダウンにこれらの携帯電話の崩壊にしている.
import { Controller } from "@hotwired/stimulus";
import { Turbo } from "@hotwired/turbo-rails";

/*
 * Usage
 * =====
 *
 * add data-controller="navigation-select" to common ancestor
 *
 * Action:
 * data-action="change->navigation-select#change"
 *
 */
export default class extends Controller {
  change(event) {
    const url = event.target.value;
    Turbo.visit(url);
  }
}

コントローラ
これは、ハピでチームを作成するときに使用されます.@ prioritysupportで終わるカスタム電子メールアドレスを選択しなければなりません.NETは、私たちが事前にあなたの会社名でこの入力を入力したいのは、UXビットをニッチにする.

import ApplicationController from "./application_controller";

/*
 * Usage
 * =====
 *
 * add data-controller="slugify" to common ancestor or form tag
 *
 * Action (add to the title input):
 * data-action="slugify#change"
 *
 * Target (add to the slug input):
 * data-slugify-target="slugField"
 *
 */
export default class extends ApplicationController {
  static targets = ["slugField"];

  change(event) {
    const { value } = event.target;
    this.slugFieldTarget.value = value.toLowerCase().replace(/[^a-z0-9]/, "");
  }
}

それだ!
Yepは、リッチなユーザーインターフェイスを使用してフルアプリケーション、WebSocketsとのみ8 Javascriptファイルを維持するためのライブアップデート!
ここでさらに良いことは、8つの刺激コントローラの7がコピーされることができて、他のアプリに貼られることができるということです.

どのようにHotwireを最大限に活用するには?
上記のすべての私のコントローラからおそらく、私の番号1のヒントを伝えることができるように、私の番号1のヒントは、一般的なものを維持するために、アプリケーションの特定の部分の特定のコントローラを作成するのではなく、機能を必要とするときに再利用可能な動作を収集しようとします.
それ以外のターボフレームやストリームに依存して重いリフティングを行うには、本当に必要がない限り、刺激的なコントローラを書くことを避ける必要があります、あなたが考えるかもしれないよりもターボで多くを行うことができます.
最後に、Actionableなヒントとトリックの多くのためにBetter stimulusBoring Railsをチェックしてください!