extenderを使えばいいことがわかったのでタイトルを変えた。
起きたこと
<input type="number" name="foo" min="0" data-bind="textInput: foo">
マイナスを入力できないようにしたかったため、min="0"
を設定していたのだが、実際にはマイナスにできてしまった…。たぶんmax属性を使っても上限を突破するようなことが起きるんじゃないだろうか。
対処方法
コメントで教えていただいたのだが、入力値の強制などはextenderで対応したほうがいいということだったため、再実装してみた。たしかにこのほうが汎用的でよさそう。
コメントをいただいた後に実装した方法
coffeescript
# 整数を強制するko拡張を定義
ko.extenders.integer = (target, bool) ->
return target unless bool
result = ko.pureComputed(
read: target,
write: (new_value) ->
current = target()
value_to_write = parseInt(new_value, 10)
value_to_write = 0 if isNaN(value_to_write) || value_to_write < 0
if current isnt value_to_write
# 値が変わっていたら反映
target(value_to_write)
else if current isnt new_value
# currentが100、new_valueが0100などが渡されると
# value_to_writeは100になるので値は変わらないが、
# 何もしないと0100のままになるので通知を行う必要がある
target.notifySubscribers(new_value)
).extend(notify: 'always')
result(target())
result
これを定義しておいて、observableに拡張を反映します。
coffeescript
class FooViewModel
constructor: ->
@foo = ko.observable(0).extend(integer: true)
最初に実装した方法(よくない方法)
※こちらはログとして残しているだけなので参考にしないように…。
data-bind="event: {change: check}"
を使って、値が変わったタイミングでチェックさせようかと思ったけれど、このためにわざわざメソッド作るのはどーなんだ?と思っていたところ、subscribe
で監視してはどうか?という意見をもらったのでそうした。
新しい値を数値に変換して、数値じゃない場合やマイナスの場合は0にしてしまうようにした。
coffeescript
class FooViewModel
constructor: ->
self = this
@foo = ko.observable(0)
@foo.subscribe (new_value) ->
new_value = parseInt(new_value, 10)
new_value = 0 if !$.isNumeric(new_value) || new_value < 0
self.foo(new_value)
以上です。