How to value bind datetime field with format function that checks null?

1,962 views
Skip to first unread message

wyx...@gmail.com

unread,
Mar 20, 2014, 3:01:15 AM3/20/14
to knock...@googlegroups.com
I do bind like
<input data-bind="value: moment(datefield1).format('ll')">

since datefield1 could have null value, it doesn't work.

I then define a function
    formatDateTime: function (dateTime, formatting) {
          if (dateTime == null || dateTime == '') {
            return null;
          } else {
            return moment(dateTime).format(formatting);
          }
        }

and bind like

<input data-bind="value: formatDateTime(datefield1,'ll')">

it displays fine, but it doesn't observe right. 

Any idea I can display it right and also keep it observable?

Thanks

Patrick Steele

unread,
Mar 20, 2014, 7:22:42 AM3/20/14
to knock...@googlegroups.com
This is a perfect place for a custom binding handler.  Here's an example of one for moment:


--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

wyx...@gmail.com

unread,
Mar 20, 2014, 12:52:38 PM3/20/14
to knock...@googlegroups.com
That doesn't work for me, it is the same result as my own function, that it displays fine but not observable right.
 
      ko.bindingHandlers.moment = {
        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
          var val = valueAccessor();

          var formatted = null;
          var date = moment(ko.utils.unwrapObservable(val));

          var format = allBindingsAccessor().format || 'MM/DD/YYYY';

          if (date && date.isValid()) {
            formatted = date.format(format);
          }

          element.innerText = formatted;
        }
      };


The below doesn't save right, it is a Jquery UI date picker

<input data-bind="moment:sampleReceivedDate, event{change :$parent.save}" class="datepicker">

But this works fine
<input data-bind="value:sampleReceivedDate, event{change :$parent.save}" class="datepicker">

Patrick Steele

unread,
Mar 20, 2014, 1:57:34 PM3/20/14
to knock...@googlegroups.com
You probably need to have an init handler too to set up the event monitoring on the textbox so updates ARE reflected in your view model.  Since you don't need to do anything special, you could delegate to the built-in "value" binding handler:

iinit: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
}

Then again, if you want to keep the data stored a certain way and just expose it for reading/writing in a different format, a writeable computed observable may work better (http://knockoutjs.com/documentation/computedObservables.html).

wyx...@gmail.com

unread,
Mar 20, 2014, 3:12:14 PM3/20/14
to knock...@googlegroups.com
Thanks, but it doesn't work neither with the init.
So sampleReceivedDate is one field of project object, projects is an array

     var projects = ko.observableArray();
....
      <tbody data-bind="foreach: projects"><tr>
          <td style="text-align: center;"><input data-bind="moment:sampleReceivedDate, event{change :$parent.save}" class="datepicker"></td>
....

 then in save function, I check the first item which is one I pick a different date,  the date doesn't change if I bind this way, it changes when I bind with value:, do you see what is the problem?

      var save = function () {
        logger.log(projects()[0].sampleReceivedDate())
         ...
      };

Patrick Steele

unread,
Mar 20, 2014, 5:14:09 PM3/20/14
to knock...@googlegroups.com
Try this:

ko.bindingHandlers.moment = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
    },
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var val = valueAccessor();

var formatted = null;
var date = moment(ko.utils.unwrapObservable(val));

var format = allBindingsAccessor().format || 'MM/DD/YYYY';

if (date && date.isValid()) {
formatted = date.format(format);
}

        valueAccessor()(formatted);
ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel);
}
};



wyx...@gmail.com

unread,
Mar 20, 2014, 7:57:01 PM3/20/14
to knock...@googlegroups.com, wyx...@gmail.com
Thanks, it does work well in jsFiddler, but not for me, I found out that could be affected by what I did to load knockout by requirejs, conflict result, it seems custom handler does work in some way, but doesn't work like it does in jsFiddler.
Reply all
Reply to author
Forward
0 new messages