Modifications to Cubiq dot org’s Spinning Wheel Control (Updated)

Working with the UIPickerView isn’t too bad, but if you’d rather work with cool web technology like CSS3, then this control’s for you. Plus it gives you a nice basis for a very customizable picker control.
 

UPDATE 09-21-2012: The demo stopped working and I suspect it has something to do with possibly Apple removing mouse events from iOS6. I included touchend events in tandem with the mouseup event to show the SpinningWheel control and all is well now.

UPDATE 09-20-2012: I forgot to mention, I also added an option to show a mask (which also includes the option of hiding the SpinningWheel control on mask tap/click).

The Spinning Wheel control was created by Matteo Spinelli, a web developer in Florence, Italy. The control works exactly like a UIPickerView in XCode, if you’re familiar with that. Working with the UIPickerView isn’t too bad, but if you’d rather work with cool web technology like CSS3, then this control’s for you. Plus it gives you a nice basis for a very customizable picker control. In my version, I’ve made four core feature additions to the control:

  1. Added mouse events, mainly so that I can troubleshoot using a desktop browser console.
  2. Added the ability to tap to select an item within a slot, which mimics UIPickerView’s behavior. Visual styling wasn’t added (such as background fade-in and fade-out on tap) but you can easily add that via CSS3 transitions.
  3. Refactored and created two new methods:
    • resetSlots – Removes all slots from the DOM and resets the slotData.
    • createSlots – Adds the slots to the DOM and sets the defaultValue. This was simply moved from the create method into a new method.
  4. Added an onchange event, which will only fire if data for any of the slots have changed.
  5. Added showMask option and closeOnMaskTap which will hide the SpinningWheel control when you tap/click on the mask.

The main purpose for me adding these features is for a label application I’m developing for work that will print out a label with datamatrix barcode onto a Zebra printer. For this example, I’m using the Wink JS framework in conjunction with the control (for the project at work I’m actually using Zepto, Wink JS, Backbone, and Underscore with no conflicts). For those interested, I’ll go over one simple example: how to change the number of days based on the month and year.

Implementation is simple, just set the setChangeAction function for the date field to utilize the resetSlots and createSlots methods whenever the month and year change. Here’s the demo link and the modified spinningwheel.js can be downloaded here.

First off, create a text field. The readonly option in the text field allows for a cleaner UX:

<label for="input-date">Date:&nbsp;</label><input id="input-date" name="input-date" type="text" readonly />

Then, bind that field to the mouseup event (I did this in the window.onload function):

document.getElementById('input-date').addEventListener('mouseup', showDateWheel, false);

There are three utility functions you’ll need for this implementation. The getCurrentDate function simply gets the current date, which you can use to populate your date field initially. The getDaysInMonth functions gets the number of days for the month given the month and year. And finally the stringPad function pads the month and days with leading zeros and is also used by the getCurrentDate function:

var getCurrentDate = function () {
  var d = new Date();
  var curr_date = d.getDate();
  var curr_month = d.getMonth() + 1; //Months are zero based
  var curr_year = d.getFullYear();
  return stringPad("0", 2, curr_month) + "-" + curr_date + "-" + curr_year;
};                                                                         

var getDaysInMonth = function (month, year) {
  return new Date(year, month, 0).getDate();
};                                                                         

var stringPad = function (pad, len, str) {
  return (Array(len).join(pad) + str).slice(len * -1);
};

Lastly, when creating your Spinning Wheel control, set the setChangeAction to the following function:

SpinningWheel.setChangeAction(function () {
  var days = {};
  var results = SpinningWheel.getSelectedValues();
  if(SpinningWheel.activeSlot == 0 || SpinningWheel.activeSlot == 2) {
    SpinningWheel.resetSlots();
    SpinningWheel.slotData[1].values = undefined;
    for( var i = 1; i <= getDaysInMonth(results.keys[0], results.values[2]); i += 1 ) {
      days[i] = i;
    };
    SpinningWheel.slotData[1].values = days;
    SpinningWheel.createSlots();
  };
});

Hope this saves someone a few hours…happy coding!

See cubiq.org