bretcj7
bretcj7

Reputation: 355

Best way to use datetimepicker with Backbone model?

I'm currently using the jquery datetimepicker inside a backbone view that will have a model tied to it for each datepicker control I use.

I'm not sure what the best way to implement this but there is huge rendering slowness issues if I have more than a few datetimepicker controls in my CompositeView.

Here is my current setup, ideas on ways to make this faster or change would be appreciated.

There looks to be a bottle neck in the JQuery _updateDatePicker code as well. empty() eventually calls $.cleanData which is a choke.

    /* Generate the date picker content. */
     _updateDatepicker: function(inst) {
             this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
             instActive = inst; // for delegate hover events
             inst.dpDiv.empty().append(this._generateHTML(inst));

Underscore template code:

<div style="float:left;">           
    <div class="lbltext" id="startdate-datepicker"></div>                
</div>

CompositeView onRender:

            onRender: function () {
            // Add datetimepicker               
            var dtp_mod = Page.Module("datetimepicker");

            this.dateTimePickerDailyStart = new dtp_mod.View({
                model: new dtp_mod.Model({
                    CurrentDate: null,
                    LabelText: "Start Date",
                    showTimepicker: false

                }),
                el: this.ui.dailystartdatepicker[0]
            }).on("change.datetimepicker", this._onDateChange, this);

Upvotes: 0

Views: 2233

Answers (1)

Wilbert van de Ridder
Wilbert van de Ridder

Reputation: 752

Alright, took a stab at this. See fiddle: http://jsfiddle.net/Cardiff/SbDcZ/.

Demo notes
It will show two identical views which can be reloaded using a button. This is to demonstrate the onClose functionality of the view. It also shows that the views are synced and display the latest set value.

Datetimepicker specific code

// Itemview (line 16 in jsfiddle)
var movieItemView = Marionette.ItemView.extend({
    tagName: "li",
    className: 'listItem',
    template: "#movie-list-item",
    ui: {
        dateInput: '.datetimepicker'
    },
    onShow: function () {
        // Invoke the datetimepicker plugin
        this.ui.dateInput.datetimepicker({
            // Lazy init to prevent a lot of instances right away
            lazyInit: true,

            // Proxy the callback function to retain view scope
            onChangeDateTime: $.proxy(this.changeDate, this)
        });
    },
    changeDate: function (dp, $input) {
        this.model.set('date', $input.val());
    },
    onClose: function () {
        // Destroy the datetimepicker plugin
        this.ui.dateInput.datetimepicker('destroy');
    },
    modelEvents: {
        'change:date': 'updateDate'
    },
    updateDate: function () {
        // Check if we need to update the date. 
        var modelDate = this.model.get('date');
        if (modelDate != this.ui.dateInput.val()) {
            this.ui.dateInput.val(modelDate);
        }
    }
});

Implementation notes

  • Define the input element using the ui attribute to provide easy access.
  • Use of onShow method before instantiating the plugin. This assumes the datetimepicker plugin is dom-dependent. If you do this in the onRender function, dom-dependent plugins may not work as intended.
  • Instantiating the plugin using the lazyInit option which is supposed to be beneficial in long(er) lists.
  • Using a proxy for the onChangeDateTime function to stay in the view scope and provide easy access to the view's model.
  • Destroy the datetimepicker plugin on view closing. This (generally) prevents zombies.
  • Listen to `change:date' to check whether the value has changed.
  • In updateDate first check if we really need to update the value in this view. In this case this check is not really necessary, however if you're using plugins which require re-initialization on value changes or any other heavy actions it may be beneficial to check if you really need to do this.

Upvotes: 1

Related Questions