Knockout.jsのko.utilsが地味に便利

小粒なアプリケーションばかりを書いているので、クライアントサイドMVCを実装したい時も小粒なライブラリであるところのKnockout.jsを使っています。

Knockout.jsはMVVMのパターンを提供するライブラリなのですが、今回は詳細を書きません。
知りたい方は公式のチュートリアルとかがとても親切でいい感じなのでそこから見たらいいのではないでしょうか。

今回はko.utilsの話

で、Knockout.jsのドキュメント上では目立たないのですが、Knockout.jsに標準で添付しているko.utilsが地味に便利です。
まあjQueryがあればどうってことのない機能もあります。jQueryと合わせて使っていない場合とかには非常に助かるので備忘録的に残します。

ちなみに公式のドキュメントからもリンクされているKnock Me Outというブログを参考にしました。
ライブラリの作者の方なんですかね?

全部書くと膨大な量になるので、とりあえず今回利用した ko.utils.array* 系に絞ります。

ko.utils.arrayFilter

配列をフィルターしてフィルターに該当する要素のみの配列を返します。
検索とかに使えそうです。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'fuga'])
  @filter = (filter) ->
    filteredArray = ko.utils.arrayFilter @sampleArray(), (str) ->
      filter.test str

第1引数に配列を渡すと第2引数の関数に一個ずつ配列の中身を渡してくれます。 関数の中でtrueを返した要素のみの配列が戻り値になります。

ko.utils.arrayFirst

arrayFilterとほとんど変わらないです。
フィルターに該当する最初の要素を返します。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'fuga'])
  @filter = (filter) ->
    filteredArray = ko.utils.arrayFirst @sampleArray(), (str) ->
      filter.test str
    , sampleViewModel

コードもほとんど変わらないですね。
こちらは何故か第3引数にフィルター関数を実行するオブジェクトを指定できます。

ko.utils.arrayForEach

普通のforEachです。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'fuga'])
  @alertAll = ->
    ko.utils.arrayForEach @sampleArray(), (str) ->
      alert str

特にいうことないですね…。

ko.utils.arrayGetDistinctValues

配列の中でユニークな値だけを取り出した配列を返します。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'foo'])
  @unique = ->
    ko.utils.arrayGetDistinctValues @sampleArray() # -> ['foo', 'bar', 'hoge']

ブログシステムでカテゴリタグとかつけるときに使えるでしょうか。

ko.utils.arrayIndexOf

配列の中である要素の位置を探して返します。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'foo'])
  @index = (obj) ->
    ko.utils.arrayIndexOf @sampleArray(), obj

ちなみに同じ要素が配列に入っている場合、先に見つかった方を返します。
該当する要素がない場合は-1を返します。

ko.utils.arrayMap

普通のMapです。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'foo'])
  @mappedArray = ->
    ko.utils.arrayIndexOf @sampleArray(), (str) ->
      'mapped' + str

第1引数で与えられた配列の各要素に第2引数の関数を実行し、関数の戻り値で新しい配列を作ります。

ko.utils.arrayPushAll

配列に配列を継ぎ足します。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'foo'])
  @pushedArray = (array) ->
    ko.utils.arrayPushAll @sampleArray(), array # -> ['foo', 'bar', 'hoge', 'foo', array[0], array[1], ...]

ko.utils.arrayRemoveItem

配列から指定した要素を削除します。

class sampleViewModel
  @sampleArray = ko.observableArray(['foo', 'bar', 'hoge', 'foo'])
  @removedArray = ->
    ko.utils.arrayIndexOf @sampleArray(), 'foo' # -> undefined
    @sampleArray()                              # -> ['bar', 'hoge', 'foo']

まとめ

observableArrayとかで配列を多く扱うことがあるので、ko.utils.array*系は覚えておくと便利。