firefox/chrome web browser date input

Using date inputs in Chrome and Firefox work differently. Chrome (and Opera) comply with the HTML5 RFC3339/ISO8601 specifation for date, and it will display it in the browsers locale, with a date picker.

Firefox (and most other browsers) don’t support it.

Below is a simple way of detecting type=’date’ support.

1
2
3
4
5
6
7
8
// Datepicker
var elem = document.createElement('input');
elem.setAttribute('type', 'date');
 
if (elem.type === 'text')
{
$('#transactionDate').datepicker();
}

It will attempt set up a date input. If type falls back to ‘text’ it doesnt support dates. Or if you have Modernizr then just do

1
 if(Modernizr.inputtypes.date){...

WHY THIS IS A PROBLEM:
Chrome is expecting and sending back dates in the YYYY-MM-DD format, and displaying them in the local (e.g dd/mm/yyyy) – so whats displayed is not what is sent. Other browsers are sending back the displayed value – so you either show dates in the browser as YYYY-MM-DD as the date, so the fromat is known at the server, or deal with ambigious date formats.
SOLUTION:
Standardize the ‘wire’ format (to the HTML5 specification; YYYY-MM-DD).
On browsers that dont support date, clone your input and hide it, use this for the ‘wire value’. With the original, append ‘-display’ to the id and name attributes. This is what the user sees.

It turns out that the JQuery-UI datepicker has an altField and altFormat in addition to the target control and dateFormat, so the some of the work has been done for us.
The bootstrap datepicker doesnt have these extras. If I needed to use it I would try something like this:

1
2
3
$( "#form_id" ).submit(function( event ) {
// convert and copy display date to the hidden feild.
}

(havent tried this – Ive no idea if any “gotcha’s” are waiting)

So the block below will display in dateFormat and transfer dates in ISO9660 format to the server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (!Modernizr.inputtypes.date)
{
// alert("This browser has no datepicker support");
$('input[type=date]').each(function (index, element) {
/* clone the input, then hide it.
This will contain the 'wire-value' in ISO8660 format (yyyy-mm-dd) */
var clone = $(this).clone();
clone.insertAfter(this);
clone.hide();
/* Rename the original field, this contains the 'display-value' */
$(this).attr('id', $(this).attr('id') + '-display');
$(this).attr('name', $(this).attr('name') + '-display');
 
/* Create the datepicker with the desired display format,
then format the alt field to ISO8660 and point it at the hidden clone */
$(this).datepicker({
dateFormat: "dd/mm/yy",
altField: "#" + clone.attr("id"),
altFormat: "yy-mm-dd",
changeMonth: true,
showButtonPanel: true,
changeYear: true});
 
/* Finally, parse the value and change it to the display format */
if ($(this).attr('value')) {
var date = $.datepicker.parseDate("yy-mm-dd", $(this).attr('value'));
$(this).attr('value', $.datepicker.formatDate("dd/mm/yy", date));
}
});
}

The above works fine if your page is either loaded with a date value or is blank.
If you are setting the date value with script, you need to manually populate the display input

1
2
3
4
5
6
7
8
9
function populateDisplay(control)
{
if (!Modernizr.inputtypes.date)
{
var date = $.datepicker.parseDate("yy-mm-dd", $(control).attr('value'));
var display = '#'+ $(control).attr('id') + '-display';
$(display).val($.datepicker.formatDate("dd/mm/yy", date));
}
}

and call it by something like the following

1
2
3
4
// the code that is setting the date
$("#thedate").val("2016-01-21");
// calls the function to fill the display box if it exists
populateDisplay($("#thedate"));

Of course this has issues still, such as users can put garbage into the date display and have the original date post back.

NOTE: There are a lot of solutions for this. Many are bodges. If the solution is happening on the server side and its looking at the user-agent — Its a bodge. I found this on Stack overflow.(along with a lot of bad solutions)

Convert a Large Switch Method to a Factory

Say you have a switch statement with large blocks of code in it.
See the example below.(and use your imiganation)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
public enum SHAPES { Circle, Square, Rectangle, Triangle };
 
public class SwitchMethod
    {
        public static void draw(SHAPES shape)
        {
            switch (shape)
            {
                case SHAPES.Circle:
                    // 1000 lines of code...
                    Console.WriteLine("Circle.draw()");
                    break;
 
                case SHAPES.Rectangle:
                    // 1000 lines of code...
                    Console.WriteLine("Rectangle.draw()");
                    break;
 
                case SHAPES.Square:
                    // 1000 lines of code...
                    Console.WriteLine("Square.draw()");
                    break;
 
                case SHAPES.Triangle:
                    // 1000 lines of code...
                    Console.WriteLine("Triangle.draw()");
                    break;
            }
        }
    }

And you call it like this:

1
2
3
4
5
6
7
8
9
 
   class Program
    {
        static void Main(string[] args)
        {
            SwitchMethod.draw(SHAPES.Circle);
            Console.ReadKey();
        }
    }

PROBLEM:
[1] You have a large file, making it hard to understand.
[2] The Single responsibility principle is violated. 1 class – many shapes.
If you have one developer working on tirangles and another on Circles. There is going to be a conflict at check-in, (no matter what source control system you are using)

SOLUTION:
[1] Break up the switch cases into classes.
* Each class should implement a common interface.
* Each class should be in its own file.

[2] Now we need a clean method to call them.
* Add a Boolean canDraw(SHAPES shape) to the interface.
* The class returns true if it can draw the shape.

1
2
3
4
5
6
7
  public enum SHAPES { Circle, Square, Rectangle, Triangle };
 
    public interface Shape
    {
        Boolean canDraw(SHAPES shape);
        void draw();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
   public class Circle : Shape
    {
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Circle;
        }
 
        public void draw()
        {
            Console.WriteLine("Circle.draw()");
        }
 
    }
 
    public class Square : Shape
    {
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Square;
        }
 
        public void draw()
        {
            Console.WriteLine("Square.draw()");
        }
 
    }
 
    public class Rectangle : Shape
    {
 
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Rectangle;
        }
 
        public void draw()
        {
            // 100 lines of code...
            Console.WriteLine("Rectangle.draw()");
        }
 
    }
 
    public class Triangle : Shape
    {
 
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Triangle;
        }
 
        public void draw()
        {
            // 100 lines of code...
            Console.WriteLine("Triangle.draw()");
        }
    }

[3] Now make a shapeFactory.
* Make a static List containing instances of each class.
* add a getter that returns the first class that canDraw the shape.

The List/canDraw are replacing the switch. CPU cycles have been exchanged for readability.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
    public abstract class ShapeFactory
    {
        private static List shapelist = new List(){
            new Circle(),
            new Square(),
            new Rectangle(),
            new Triangle()
        };
        public static Shape getShape(SHAPES name)
        {
            return shapelist.First(a => a.canDraw(name));
        }
    }

And we call it like this…

1
2
3
4
5
6
7
8
9
class Program
    {
        static void Main(string[] args)
        {
 
            ShapeFactory.getShape(SHAPES.Circle).draw();
            Console.ReadKey();
        }
    }

One note, you could do away with the factory class and canDraw and just call an instance of a shape from within the SwitchMethod cases.