Search code examples
knockout.jscustom-binding

valueAccessor() returning function signature instead of value during custom binding creation


I'm brand new to Knockout.js and have been following a tutorial. However, my code is not working as expected, because in my custom binding createDecimal, valueAccessor() is returning the signature of the function instead of the actual value.

I'm using the latest version of Knockout.js as of today, v3.4.2.

<p>First Name <strong data-bind="text: firstName"></strong></p>
<p>Last Name <strong data-bind="text: lastName"></strong></p>
<p>Change First Name <input data-bind="value: firstName, valueUpdate: 'afterkeydown'" type="text" name="firstName"></p>
<p>Change Last Name <input data-bind="value: lastName, valueUpdate: 'afterkeydown'" , type="text" name="lastName"></p>
<p>Full Name: <strong data-bind="text: fullName"></strong></p>
<p>Add new hobby: <input data-bind="value: hobby, valueUpdate: 'afterkeydown'" type="text" name="hobby"><button data-bind="click: addHobby">Add</button></p>
<p>Hobby to possibly be added: <strong data-bind="text: hobby"></strong></p>
<ul data-bind="foreach: hobbies">
  <div>
    <li data-bind="text: $data"></li>
    <button data-bind="click: $parent.removeHobby">Remove Hobby</button>
  </div>
</ul>
<p>Total Number of Properties: <strong data-bind="makeDecimal: numberOfHobbies"></strong></p>

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script type="text/javascript">
  ko.bindingHandlers.makeDecimal = {
    update: function(element, valueAccessor) {
      var numberOfHobbies = valueAccessor();
      console.log("Number of Hobbies", numberOfHobbies);
      var formattedText = "$" + numberOfHobbies.toFixed();
      element.innerText = formattedText;
    }
  };

  function IndexViewModel() {
    var self = this;
    self.firstName = ko.observable("George");
    self.lastName = ko.observable("Lopez");
    self.hobby = ko.observable();
    self.hobbies = ko.observableArray(["Acting", "Joking", "Speaking"]);
    self.addHobby = function() {
      self.hobbies.push(self.hobby());
    };
    self.removeHobby = function(hobby) {
      self.hobbies.remove(hobby);
    };

    self.fullName = ko.computed(function() {
      return self.firstName() + " " + self.lastName();
    });

    self.numberOfHobbies = ko.computed(function() {
      return self.hobbies().length;
    });

  }

  ko.applyBindings(new IndexViewModel());
</script>


Solution

  • It's not natural, but here you need to use ko.unwrap() to get the value of the observable.

    ko.bindingHandlers.makeDecimal = {
        update: function(element, valueAccessor) {
            var numberOfHobbies = ko.unwrap(valueAccessor());
            console.log("Number of Hobbies", numberOfHobbies);
            var formattedText = "$" + numberOfHobbies.toFixed();
            element.innerText = formattedText;
        }
    };
    

    It's because of the way Knockout manage observables, by replacing them by functions.