Pages

giovedì 7 marzo 2013

How to add a "Clear" button (or whatever you want) to jQuery UI's datepicker.

In a perfect world everybody would have an IQ at least equal than a sea sponge. Sadly, is not like this and we have to see a world where people still votes for Berlusconi and people that tries to insert dates haphazardly in our Web Application. Unfortunately we have no hope for the first problem, but for the second God gave us a powerful tool to face them: JQuery UI e it's datepicker.

This tool is useful against the dangerous criminals that enjoys putting "31/Feb/2040" as birth date, but has a little flaw: there's no "Clear" feature.

After seconds and seconds of meditation, i decided to take the screwdriver and put the hands on the jquery UI code to let it work as I wish. all it takes it's two simple steps and less that 100 chars of code:

the final result.
  • Add the functionality to the datepicker's handlers. In other words, exists a function called "_attachHandlers" that creates every command that will be called through the buttons placed inside the datepicker. All we gotta do is adding the indicated lines of code inside this function.

     _attachHandlers: function(inst) {
      var stepMonths = this._get(inst, "stepMonths"),
       id = "#" + inst.id.replace( /\\\\/g, "\\" );
      inst.dpDiv.find("[data-handler]").map(function () {
       var handler = {
        prev: function () {
         window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, -stepMonths, "M");
        },
        next: function () {
         window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, +stepMonths, "M");
        },
        hide: function () {
         window["DP_jQuery_" + dpuuid].datepicker._hideDatepicker();
        },
        today: function () {
         window["DP_jQuery_" + dpuuid].datepicker._gotoToday(id);
        },
        // ******** THIS IS THE FUNCTIONALITY ADDED **********
        clear: function () {
            window["DP_jQuery_" + dpuuid].datepicker._clearDate(id); 
        },
        // ********************************************************************    
        selectDay: function () {
         window["DP_jQuery_" + dpuuid].datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
         return false;
        },
        selectMonth: function () {
         window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "M");
         return false;
        },
        selectYear: function () {
         window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "Y");
         return false;
        }
       };
       $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
      });
     }
    
    
    

    The "clear" function is very simple: it just calls the _clearDate function from the datepicker to clear the value.

  • Add the button and link it to the brand new functionality: to do this we need to modify another function called "_generateHTML" to add to the button bar the html representing the button. Two attributes needs to be added to the button to let it link to the functionality just created above: the first is "data-handler" and it represents the name of the function to call ("clear" in our case) and "data-event" that represents the event of the HTML element that fires that functionality (in our case a boring but effective "click"). This is translated to the following code

      //********** old code
      buttonPanel = (showButtonPanel) ? "
    " + (isRTL ? controls : "") + (this._isInRange(inst, gotoDate) ? "" : "") //********** ADD THIS LINE + "" //****************** + (isRTL ? "" : controls) + "
    " : "";

    That's it. It doesn't take to much to achieve that. My example was limited to the "clear" function, but the same proceedings can be used to add new functionalities such as "copy value" functions or other stuff.

4 commenti:

  1. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  2. Hi, I liked this solution except the fact that it's necessary to modify external jquery code in jquery ui library.
    I made the script which takes original functions and adds only the custom stuff, clear button in this case.

    var attachHandlers = $.datepicker._attachHandlers;
    var generateHTML = $.datepicker._generateHTML;

    $.datepicker._attachHandlers = function (inst) {

    // call the cached function in scope of $.datepicker object
    attachHandlers.call($.datepicker, inst);

    // add custom stuff
    inst.dpDiv.find("[data-handler]").map(function () {
    var handler = {
    clear: function () {
    var id = "#" + inst.id.replace(/\\\\/g, "\\");
    $.datepicker._clearDate(id);
    $.datepicker._hideDatepicker();
    }
    };
    if (handler[this.getAttribute("data-handler")]) {
    $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
    }
    });
    };
    $.datepicker._generateHTML = function (inst) {

    //call the cached function in scope of $.datepicker object
    var html = generateHTML.call($.datepicker, inst);
    var $html = $(html);
    var $buttonPane = $html.filter("div.ui-datepicker-buttonpane.ui-widget-content");

    $buttonPane.append($("<button />")
    .text("Clear")
    .attr("type", "button")
    .attr("data-handler", "clear")
    .attr("data-event", "click")
    .addClass("ui-datepicker-clear ui-state-default ui-priority-secondary ui-corner-all"));

    return $html;
    };

    RispondiElimina
    Risposte
    1. Hello,
      I found both of your methods very interesting and that Martin's less invasive code could simply be dropped into the latest version of JQuery UI's Datepicker, v1.12.0, and it works fine.

      So thank you to both of you for making this available.

      One question: The Clear button looks like it it inactive, I successfully change to the Today button using this code, which I expected would also change the Clear button, but it only worked for the Today button:


      /* Override Clear button style */
      .ui-datepicker-clear,
      /* Override the Today/Selected button style */
      .ui-datepicker div.ui-datepicker-buttonpane button.ui-datepicker-current {
      font-weight: bold;
      opacity: 1;
      filter: Alpha( Opacity = 100 );
      }


      Do either of you know what I should but into the style selector to affect the Clear button?

      Thanks again,
      Howard Brown
      howardb3115@gmail.com

      Elimina
  3. I answer to an old post, but it maybe be usefull to others:
    To display the "active" state of the close button,
    change the class added in the last row of Martin's script:
    FROM
    .addClass("ui-datepicker-clear ui-state-default ui-priority-secondary ui-corner-all"));
    TO
    .addClass("ui-datepicker-clear ui-state-default ui-priority-primary ui-corner-all"));

    RispondiElimina