0

I am trying to create a page using knockout, the model contains an observable array. One of the properties in each array item is a date, and I am trying to use a jquery ui datepicker.

I found an example of a custom bindingHandler for a datepicker in this question. However, when I tried to use it in my code, I get a javascript error during the change event handler.

My simplified code:

<table>
    <thead>
        <tr>
            <th>My Date</th>
        </tr>
    </thead>
    <tbody data-bind='foreach: visits'>
        <tr>
            <td><input data-bind='datepicker: MyDate' /></td>
        </tr>
     </tbody>
</table>

<script type="text/javascript">
    ko.bindingHandlers.datepicker = {
        init: function(element, valueAccessor, allBindingsAccessor) {
           $(element).datepicker({ dateFormat: 'dd/mm/yy' });

           //handle the field changing
           ko.utils.registerEventHandler(element, "change", function() {
               //get the value accessor
               var observable = valueAccessor();

               //assign the observable value - code breaks here with 'Function expected'
               observable($(element).datepicker("getDate"));
            });

            //handle disposal (if KO removes by the template binding)-
            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                $(element).datepicker("destroy");
            });

        },
        update: function(element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());

            //handle date data coming via json from Microsoft
            if (String(value).indexOf('/Date(') == 0) {
                value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
            }

            var current = $(element).datepicker("getDate");

            if (value - current !== 0) {
                $(element).datepicker("setDate", value);
            }
        }
    };

    var VisitModel = function(visits) {
        var self = this;
        self.visits = ko.observableArray(visits);

        self.getVisitsJSON = function() {
            return ko.utils.stringifyJson(self.visits);
        }
     };

     var visitModel = new VisitModel([{"MyDate":"01/01/2013"}]);
     ko.applyBindings(visitModel);
</script>

As in the comments in my code, I get an error saying 'Function expected' when I call observable($(element).datepicker("getDate")); . I am quite new to knockoutjs and I am not sure why I am getting this error, can anyone help explain?

Community
  • 1
  • 1
user1573618
  • 1,696
  • 2
  • 20
  • 38
  • But the other question I linked was answered with code using exactly that line, you can see it working at http://jsfiddle.net/rniemeyer/NAgNV/ – user1573618 Aug 20 '13 at 13:32
  • The problem is that while your array is an `observableArray` the elements in it aren't. The value you've bound to is just a plain javascript object. – Matt Burland Aug 20 '13 at 13:35

1 Answers1

1

You need to wrap the contents of your array into their own view models with observable properties. Something like this might work:

var VisitModel = function(visits) {
    var self = this;
    self.visits = ko.observableArray();

    for (var i = 0; i < visits.length; i++) {
        self.visits.push(new DateModel(visits[i]);
    }

    self.getVisitsJSON = function() {
        return ko.utils.stringifyJson(self.visits);
    }
 };

 var DateModel = function(date) {
     var self = this;
     self.MyDate = ko.observable(date.MyDate);
 }

 var visitModel = new VisitModel([{"MyDate":"01/01/2013"}]);
 ko.applyBindings(visitModel);

Now when you use valueAccessor you should get back the ko.observable which is a function.

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • Thanks for the answer, I've worked it into my existing code but now when I call my getVisitsJSON method, any of the properties in the DateModel (I've called it VisitDataModel now and it has a few properties) that are observable are not included in the JSON string returned. Why might this be happening? – user1573618 Aug 20 '13 at 14:05
  • ko.utils.stringifyJson doesn't handle nested properties in an array, but I found ko.toJSON which does. Now everyone works, thank you for your help. – user1573618 Aug 20 '13 at 14:14