Formating date values for display in Can.js

315 Views Asked by At

All my dates come formatted as ISO 8601 from the backend, eg 2014-01-01T12:45:30Z. Across the application, I want to display them in different formats...

  • shorthand in tables, eg Jan 1
  • longer, more explicit format on a detailed view, eg Monday, January 1st.

Solution I made a helper where I can pass in the format. Easy enough.

can.mustache.registerHelper('formatDate', function(date, format) {
    return date() ? moment(date()).format(format) : '-';
});

Problem Now I'm implementing the bootstrap datepicker, how can I capture these requirements...

  • the date in my model is formatted as ISO
  • bind to input with can-value in template
  • display format MM/DD/YY for users and datepicker

Bonus points if I don't need to make a compute for every single date value in my models, as they're quite large and with many dates.

1

There are 1 best solutions below

4
On BEST ANSWER

Unfortunately there isn't a nice API for this(yet). However, you can achieve custom formats in a view while keeping your model properties pristine with the below code.

can.view.attr('can-somecustom-value', function(el, data) {
  var attr = el.getAttribute('can-somecustom-value'),
  value = data.scope.computeData(attr, {
    args: []
  }).compute;

  new FormattedValue(el, {
    value: value
    //value is the only one we really care about, but
    //you could specify other arbitrary options here
    //such as "format: 'MM/DD/YYYY' to be used in your __format methods below"
  });
});

var FormattedValue = can.Control.extend({
  init: function () {
    this.set();
  },

  __format: function() {
    // return formatted version of this.options.value;
  },

  __deformat: function() {
    // return this.element[0].value sans format(keeps your model pristine);
  },

  '{value} change': 'set',
  set: function () {
    if (!this.element) {
      return;
    }

    var self = this;

    setTimeout(function() {
      self.element[0].value = self.__format();
    });
  },

  'change': function () {
    if (!this.element) {
      return;
    }

    this.options.value(this.__deformat());
  }
});

This will allow you to do the following:

<input can-somecustome-value="myDateProp"/>

where "myDateProp" is an attribute on some can.Map/can.Model/etc.

This will result in the input displaying a custom string format, while someModel.attr('myDateProp') will still return the ISO format(which in turn means the ISO format will also be saved to the server).

There is some internal discussion regarding adding filters/parsers to allow control over formats specific only to view rendering.