utamaro’s blog

誰かの役に立つ情報を発信するブログ

属性付きセレクタを作成する関数を作った。

属性付きセレクタを作成する関数を作った。

jqueryである属性がついたタグを取得したいと思ったときに、セレクタをハードコーディングすることがあります。

例えば以下のようなものです。

$("div[id='hoge']")

hogeという値が動的に指定できる場合はもう少し面倒になります。

$("div[id='"+ val +"']")

たまに事故が起きるのは'が抜けていたり、"で囲えていなくてビルドがエラーになったりします。

今回はこういうことが無いように便利なutilを作りました。

Attrクラスを作成する

このクラスを使って属性指定します。

export class Attr {
  private key: string
  private val: string

  constructor(key: string, val: string) {
    this.key = key
    this.val = val
  }

  getKey() { return this.key }
  getVal() { return this.val }
}

ちなみに、僕はconstructorに引数が2つの場合はsetterを作らないようにしてます。

3つ以上になったらsetterを作成します。

属性付きセレクタを生成するためのutilを作成する

Attrクラスをimportしています。

今回はmakeAttrSelectorという関数を作りました。

import {Attr} from './Attr'

export var SelectorUtils = {
  makeAttrSelector: function(target: string, attrs?: Array<Attr>) {
    if (attrs == void(0)) {
      return target
    }
    let selector = target + (function(attrs: Array<Attr>): string {
      let result = ""
      attrs.forEach((attr: Attr, index, array) => {
        result += "[" + attr.getKey() + "='" + attr.getVal() + "']"
      })
      return result
    })(attrs)
    return selector
  }
}

属性の指定がない場合にも対応可能なように、attrs引数はオプションとしています。

このメソッドを実行すると以下のようになります。

let selector = SelectorUtils.tagAttrs(
  "#test", 
  [new Attr("A", "A"), new Attr("B", "B")]
)
console.debug(selector)

結果

#test[A='A'][B='B']

new Attr("A", "A")が面倒に思えるかもしれません。 ただし、[{key: A, val: A}, {key: B, val: B}]という方法に変えた場合、タイプミスが発生する可能性が高いです。 このような理由から今回はclassを使いました。

テスト

便利なutilを作成した場合は必ずテストを書きましょう。

多くの場所で使われることが想定できるので、誰かが修正した場合に品質を担保する必要があります。

今回はjestを使用してテストを作成しました。

import {SelectorUtils} from '../SelectorUtils'
import {Attr} from '../Attr'

describe('test', () => {
  let idAttr = "#test"

  test.each([
    [null, idAttr],
    [[new Attr("A", "A")], idAttr + "[A='A']"],
    [[new Attr("A", "A"), new Attr("B", "B")], idAttr + "[A='A'][B='B']"]
  ])("属性付きセレクタの生成テスト", (attrs, expected) => {
    let selector = SelectorUtils.tagAttrs(idAttr, attrs)
    console.log({
      actual: selector,
      expected: expected,
      args: [attrs]
    })
    expect(selector).toEqual(expected)
  })

  test("attrs引数を指定しない場合", () => {
    let selector = SelectorUtils.tagAttrs("#test")
    expect(selector).toEqual("#test")
  })
});

テストにログを出すのはなぜかと聞かれたことがあります。

私の場合は以下の理由から出しています。

  • テスト対象の関数が変更されたときにテストを修正しやすくするため