grabbag
grabbag

Reputation: 1030

why is knockout computed only called on input checkbox being cleared

When the initial value is true results in the ko.computed being called only on false new values missing all true new values.

Likewise, if the initial value is false, then ko.computed is only called on new true values.

$(function () {

            function getFormattedDate() {
                var date = new Date();
                var str = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();

                return str;
            }

            var ViewModel = function (initial_value) {

                var self = this

                self.debug_logs = ko.observableArray()

                self._my_checked = initial_value
                self.my_checked = ko.computed({
                    read: function () {
                        self.debug_logs.push({ log: "Reading value to " + self._my_checked + " " + getFormattedDate() })
                        return self._my_checked
                    },
                    write: function (value) {
                        self.debug_logs.push({ log: "Setting value to " + value + " " + getFormattedDate() })

                        self._my_checked = value
                    }
                })
            }

            ko.applyBindings(new ViewModel(true))

        })
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    <div>
         <input type="checkbox" data-bind="checked: my_checked" />  

        <ol data-bind="foreach:debug_logs">
            <li data-bind="text:log"></li>
        </ol>
    </div>

I need the computed to be called on both clearing and setting of the checkbox. This will drive other functionality not shown.

Thank you in advance

Upvotes: 0

Views: 295

Answers (1)

Jason Spake
Jason Spake

Reputation: 4304

Your computed's read function will only fire the first time and never again, because it has no observables in it to trigger an update. If you want the computed to recalculate then my_checked must be an observable.

var ViewModel = function (initial_value) {

  var self = this

  self.debug_logs = ko.observableArray()

  self._my_checked = ko.observable(initial_value);
  self.my_checked = ko.computed({
    read: function () {
      self.debug_logs.push({ log: "Reading value to " + self._my_checked() + " " + getFormattedDate() })
      return self._my_checked()
    },
    write: function (value) {
      self.debug_logs.push({ log: "Setting value to " + value + " " + getFormattedDate() })

      self._my_checked(value);
    }
  })
}

The problem you'll encounter next is that every time you write a value it will also trigger a new read, so you'll get both a 'write' log and a 'read' log every time the value is changed. You'll probably want to log only one or the other.

Upvotes: 1

Related Questions