LoginSignup
3
3

More than 5 years have passed since last update.

knockoutJSのifバインディングの罠

Last updated at Posted at 2018-03-09

はじめに

とあるhtml5 + knockoutJSでつくられているシステム開発中、knockoutJSのifバインディングではまった。
※検証に用いたKnockout.jsのバージョンは 3.4.2 です。

きほんのきほう

公式ドキュメントのifバインディングを見て、一番単純な記法だとこんな感じ。

index.html
いつも見えてるやつだぜ!
<div data-bind="if: property.aTrueValue">
 ifバインディングの評価値がtrueだったらでるぜ!
</div>
test.js
ko.applyBindings({
    property: { 
        aTrueValue:ko.observable(true)
    }
});

ふるまい

aTrueValueがtrue aTrueValueがfalse aTrueValueが存在しない
text表示 text非表示 text非表示

aTrueValueが無かったり、falseだったりするとちゃんとfalseとして評価される。ふんふん。

やべーうごき①~observableの中身で評価すると~

observableのオブジェクトでifバインディングの評価をするときほん編の通り想定通りの動きをしてくれるが、observable引数無の実体の値でifバインディングを使うと少し変な動きになる。

index.html
いつも見えてるやつだぜ!
<div data-bind="if: property.aTrueValue()">
 ifバインディングの評価値がtrueだったらでるぜ!
</div>
test.js
ko.applyBindings({
    property: { 
        aTrueValue:ko.observable(true)
    }
});

ふるまい

aTrueValueがtrue aTrueValueがfalse aTrueValueが存在しない
text表示 text非表示 text表示

存在しないのにifバインディングの評価がtrueに。。。
(2018/3/11 追記)ifバインディングはプロパティの有無まではbooleanで判定してくれるが、存在しない関数はエラーとなり、結果DOMが生成されてしまう!!

やべーうごき②~複数項目の論理式~

複数のobservableオブジェクトでifバインディングの評価をするとへんてこになる。

index.html
いつも見えてるやつだぜ!
<div data-bind="if: (property.aTrueValue && property.anotherTrueValue)">
 ifバインディングの評価値がtrueだったらでるぜ!
</div>
test.js
ko.applyBindings({
    property: { 
        aTrueValue:ko.observable(true), 
        anotherTrueValue:ko.observable(true)
    }
});

ふるまい

--- aTrueValueがtrue aTrueValueがfalse aTrueValueが存在しない
anotherTrueValueがtrue text表示 text表示 text非表示
anotherTrueValueがfalse text非表示 text非表示 text非表示
anotherTrueValueが存在しない text非表示 text非表示 text非表示

条件式の頭がfalseなのにifバインディングの評価がtrue。
(2018/3/11 追記)javascriptの論理式について盛大に勘違いしてました。functionはtrue評価されてしまうので、後方のプロパティでifバインディングが効く模様。でもプロパティが存在しない場合はfalseになる。なかなか複雑。。。

やべーうごき③~複数項目の論理式with中身評価~

複数のobservableオブジェクトの中身で評価してみる。

index.html
いつも見えてるやつだぜ!
<div data-bind="if: (property.aTrueValue() && property.anotherTrueValue())">
 ifバインディングの評価値がtrueだったらでるぜ!
</div>
test.js
ko.applyBindings({
    property: { 
        aTrueValue:ko.observable(true), 
        anotherTrueValue:ko.observable(true)
    }
});

ふるまい

--- aTrueValueがtrue aTrueValueがfalse aTrueValueが存在しない
anotherTrueValueがtrue text表示 text非表示 text表示
anotherTrueValueがfalse text非表示 text非表示 text表示
anotherTrueValueが存在しない text表示 text非表示 text表示

条件式の頭が存在しないと、trueなんだね!すっごーい!
(2018/3/11 追記)①と同様、存在しない関数はエラーとなるのと、ショートサーキット評価で上記仕様になっているみたい。

結論

ifバインディングを使う場合は
条件式のプロパティを定義したうえでobservableの中身で評価する
を守らないと想定通り動かなさそう。

参考

https://stackoverflow.com/questions/15307504/knockout-js-if-binding-on-multiple-booleans
http://kojs.sukobuto.com/docs/if-binding
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators

3
3
3

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
3
3