LoginSignup
11
5

More than 5 years have passed since last update.

Elm備忘録 ~CustomElementつかっていこうぜ[Popover編]~

Posted at

Elm備忘録 ~CustomElementつかっていこうぜ[Popover編]~

問題

  • Elmでポップオーバを使おうとおもうとModelにPopoverの状態を保持するためのフィールドがめっちゃ増えんねん。
  • 俺は嫌やねん。
    • CSSでやるという手段もあるけどまあ置いときましょう。今はBootstrapのやつがいいんです。
type alias Model = {
  titlePopoverState: Popover.State
  , columnDescribePopoverState1: Popover.State
  , columnDescribePopoverState2: Popover.State
  , columnDescribePopoverState3: Popover.State
  , columnDescribePopoverState4: Popover.State
  , columnDescribePopoverState5: Popover.State
}

  • PopoverをCustomElementにしてElmから呼び出すぞ!

PopoverをCustomElementにラップする

  • bootstrapの本家jsを使うとjqueryとお付き合いが発生するのでhttps://thednp.github.io/bootstrap.nativeを使っていくスタイルです。
  • CustomElementのお作法にそいながらconnectedCallbackでPopoverを表示するロジックを書いてdisconnectedCallbackで後片付けロジックを書きます。
  • customElements.define('x-popover', PopoverElement);のx-popoverが要素名になり
  • this.getAttribute(アトリビュート名);で指定しているアトリビュートが要素のアトリビュートとして利用できます
    • data-placementがポップオーバーがどこに出るかを指定できるアトリビュートです。 top, left, right, bottomが指定できます。
  • いろいろ端折ってますがWebpackでバンドルやで。とか脳内補完してください

const Popover = require("bootstrap.native").Popover;

/**
 * TODO クォート統一無法地帯
 * https://thednp.github.io/bootstrap.native/
 */
class PopoverElement extends HTMLElement {
  attributeChangedCallback(attr, oldValue, newValue) {

  }

  disconnectedCallback() {
    if (this.removeCloseHandler) {
      this.removeCloseHandler();
    }
  }

  isSetUped() {
    return !!this.instance;
  }

  setUpBootstrapPopover(popoverparent) {
    popoverparent.className = "fas fa-info-circle color-blue ml-5px";
    const messageAttr = this.getAttribute('data-message');
    const titleAttr = this.getAttribute('data-title');
    const placementAttr = this.getAttribute('data-placement');
    popoverparent.setAttribute("data-content", messageAttr);
    popoverparent.setAttribute("data-title", titleAttr);

    this.instance = new Popover(popoverparent, {
      template:  `<div class="popover" role="tooltip">
        <div class="arrow"></div>
        <h3 class="popover-header">${titleAttr}</h3>
        <div class="popover-body">${messageAttr}</div>
        </div>`,
      placement: placementAttr
    });

    this.removeCloseHandler = () => {
      // HOGEHOGE
    }
  }

  connectedCallback() {
    const popoverparent = document.createElement('span');
    if (this.isSetUped()) {
      return;
    }
    this.setUpBootstrapPopover(popoverparent);
    this.appendChild(popoverparent);
  }
}

customElements.define('x-popover', PopoverElement);

Elmで呼び出しを定義する

  • Html.node "x-popover" [] []でCustomElementを呼び出すようにしてやる
  • Attr.attribute "attr" "value"でアトリビュートを指定する
  • PlacementをCustomElementで宣言するのはElmって感じでいいですね。

module Popover exposing (view, Config, Placement(..))

import Html
import Html.Attributes as Attr

type Placement
    = Top
    | Bottom
    | Right
    | Left


placementToString : Placement -> String
placementToString pl =
    case pl of
        Top ->
            "top"

        Bottom ->
            "bottom"

        Right ->
            "right"

        Left ->
            "left"


type alias Config =
    { title : String
    , message : String
    , placement : Placement
    }



view : Config -> Html.Html msg
view { title, message, placement } =
    Html.node "x-popover" -- ここがミソ
        [ Attr.attribute "data-message" message
         , Attr.attribute "data-title" title
         , Attr.attribute "data-placement" (placementToString placement)
         ]
        []

呼び出す側

  • 下のような感じで呼び出せる
import Popover

view [] [
  Html.span [] 
    [ 
      Html.text "むずい用語や"
      , Popover.view { 
          message = "ウンタラカンタラ"
          , title = "この用語はな..."
          , placement = Popover.Top } 
    ]
]

  • CustomElementによってPopoverの状態をCustomElementに閉じ込めてElmから知らん顔できるようになった
  • Popoverに限らずElmで状態を管理する価値はないぜ!ってなったものをCustomElementにしてしまえばElmで管理する状態は減る
  • 当方DatePickerとかCustomElementにしたりしました。
    • 今回でなかったCustomElement -> Elmへのイベント通知とかDatePickerを題材に紹介しちゃいたい
  • ElmのModelで状態を持つ価値がないなぁというときにはこういうのもありないんじゃない?
11
5
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
11
5