Web Marina

日々の業務や勉強などで得た知識をアウトプットしていきます。

【jQuery】イベントオブジェクト ー親要素で発火するイベントを特定の子孫では解除したいー

f:id:song-of-life1352607:20180113005923j:plain

こんにちは、マリンです。

今回はJSでのイベントを発火させる要素の特定です。

親要素で指定するが、特定の子孫要素では実行してほしくない。

そんな時どのように指定すればよいでしょうか?

:notとか調べてみたのですが、

子孫要素でのやり方がイマイチよくわからず。。。

そこで今回はイベントオブジェクトを使ってこれを実装しました。


もっと簡単に実装できる、

セレクタとか、便利なメソッドとか、

皆様ぜひ教えてください。




概要

  • tableの概要を記述したtrをクリックした時、詳細の列が表示されるようにする。

  • trの中には承認ボタンがある。

  • 親のtrにイベントを付けているので、子要素のボタンのクリックでもshow hideが実行されてしまう。

以上のことから、子要素のボタンだけクリックイベントを外したいわけです。

最初は:notなどを使って特定しようとしたのですが、

うまくボタンだけを取ることが出きませんでした。

そこで、イベントオブジェクトを使ってみました。


詳細

サンプルコード

まずは解説に使うサンプルコードを記載しておきます。

<form action="sample/create" method="post">
    <table class="table">
        <tr id="sample-tr">
            <td>Name: Yamada Hanako</td>
            <td>Age: 20</td>
            <td><button name="approve" type="submit" value="approve">承認</button></td>
        </tr>
        <tr id="sample-hidden-tr style="display: none">
             <td>Address: Tokyo Minato-Ku</td>
             <td>Email: sample@example.com</td>
             <td>Password: password</td>
        </tr>
    </table>
</form>

上段のtrが表示されている行。

下段のtrが非表示部分で、上段をクリックすると表示されます。

しかし、上段3つ目のカラムにあるボタンだけはクリックの対象外にします。


以下が今回のCoffeeです。

$('#sample-tr').on 'click', (e)->
    target = $(e.target)
    if target[0].nodeName == "BUTTON"
        return
    if $(@).hasClass('show')
        $(@).removeClass('show')
        $('#sample-hidden-tr').hide()
    else
        $(@).addClass('show')
        $('#sample-hidden-tr').show()
    retrun




詳細解説

HTMLは省略します。

$('#sample-tr').on 'click', (e)->
    target = $(e.target)

まずは最初の2行です。

1行目は上段trへのクリックイベントで、引数eがイベントオブジェクトです。


2行目はイベントが発生したjQueryオブジェクトを変数に入れています。

targetの中身は以下のようになっています。

target: jQuery.fn.init(1)
  0: button
    accessKey: ""
    assignedSlot: null
    attributeStyleMap: StylePropertyMap {size: 0}
    attributes: NamedNodeMap {0: type, 1: name, type: type, name: name, length: 2}
    autocapitalize: ""
    .
    .
    .
    nextElementSibling: null
    nextSibling: null
    nodeName: "BUTTON"
    nodeType: 1
    .
    .
    .




次の2行です。

if target[0].nodeName == "BUTTON"
    return

if文でイベントが発生した要素がボタンだったら何もしないで終了させています。


if文の内容と、先ほどのtargetの中身を見比べてみてください。

target: jQuery.fn.init(1)
  0: button
    accessKey: ""
    .
    .
    .
    nodeName: "BUTTON"
    .
    .
    .
target[0].nodeName == "BUTTON"

イベントオブジェクトのtarget

その中に入っているキー[0]でDOM要素を取得し、

さらにその中からnodeNameプロパティで対象となった要素名を取得します。

そして、要素名が"BUTTON"だったら何もせずreturnというわけです。


ちなみに、最初にe.targetを変数targetに入れましたが、

今回のような単純なコードでしたら入れる必要もないと思います。

if $(e.target)[0].nodeName == "BUTTON"

でいけます。

個人的に見やすかっただけです、、、


まとめ

今まで苦手意識のあったイベントオブジェクトやjQueryオブジェクトでしたが、

一度じっくり眺めてみるとなんとなく解ってきました。

やはりぱっと見よくわからない!と思っても、

テンパることなく冷静に眺めていることって必要ですね。

余談ですが、今回のことで

なぜ$()を使ってjQueryオブジェクトにするのか?

ということが今更ながら理解できました。

根本が解っていないと理解が遅くなる一方ですね。。。

まだまだ奥が深いと思うので、これを機にちゃんと勉強してみます。