Category Archives: Web development

Programming, CSS, and general web stuff.

Using jQuery Datepicker and Dialog Box To Select Date Range

Using a jquery datepicker in a jquery dialog box to select a date range is a handy, slick way of having users input dates. Date handling and validation in forms when input by the user can be tricky at best.

Here a modal dialog box will be used to allow the user to select a date range. That date range will be validated to ensure that it goes from a start date that is prior to the end date. Also, an alternate field will be populated by the datepicker that formats the dates in a specific way. This can be helpful if you are using the dates in a database query or other call that requires a certain format.

First we put a button to open the dialog box and the dialog box itself on the page:

<button id="selectDateRange">Select Date Range</button>	 

<div id="dialog" title="Select Date Range">
<div id="message"></div>
	<form name="dateRange" id="dateRangeForm" action="index.php" method="post">
    <label for="startdate">Start Date</label>
    <input id="startdate" type="text" readonly /><input type="hidden" name="startdate" 

id="start_alternate" />
    <label for="enddate">End Date</label>
    <input id="enddate" type="text" readonly /><input type="hidden" name="enddate" id="end_alternate" 

/>
    </form>
</div>

A message div is in the dialog box to send the user success or error messages related to their date selection. The input boxes are set to readonly so the user cannot type in a date; they must use the datepicker.

Then the jquery to set the datepicker to the appropriate input box in the dialog box, specify the alternate field and format, and specify min and max dates:

$("#startdate").datepicker({altField: '#start_alternate',altFormat: 'yy-mm-dd',minDate: '-1y',maxDate: -1});

$("#enddate").datepicker({altField: '#end_alternate',altFormat: 'yy-mm-dd',minDate: '-1y',maxDate: -1});

The minDate is set to a year from today (user cannot go back more than a year) with ‘-1y’ and the maxDate is set to yesterday (user cannot pick today or a future date) with -1. Check the jQuery documentation on the datepicker min and maxDates for further explanation.

And, of course, the code for the button that opens our dialog box:

$('button#selectDateRange').click(function(){
		$('#dialog').dialog('open');
	});

The dialog box code does several things including:

  • Closing the datepicker when the dialog closes
  • Checking for values in the input boxes
  • AJAX post to validate the date range (alternate javascript validation of date range included below)
  • Displaying a message to the user after validating the date range
  • Sets the additional dialog close button functions
$('#dialog').dialog({
    autoOpen: false,
    width: 400,
    modal: true,
    resizable: false,
    close: function() {
        $('#message').html("");
	    $('#dateRangeForm :input').each(function() {
	    $(this).val('');
	});
    },
    buttons: {
        "Close": function() {
            $(this).dialog("close");
	        $('#message').html("");
	        $('#dateRangeForm :input').each(function() {
	        $(this).val('');
	    });
	},
	"Submit": function() {
	    var errors = 0;
        $('#dateRangeForm :input').each(function() {
	        if($(this).val() == ''){
		       $(this).prev().prev().css("color", "red");
		       $(this).prev().val('Click box and use calendar to enter date.');
		       errors++;
		   } else {
		       $(this).prev().css("color", "black");
		   }
	   });

	  if (errors == 0){
	      dataString = $('form').serialize();
            $.ajax({
			    type: "POST",
			    url: "dateRange.php",
			    data: dataString,
			    dataType: "json",
			    success: function(data) {
			        if(data.error == "invalid"){
				    $('#message').html("<div class='errorMessage'>Date range is invalid.</div>");
			        } else {
				    $('#message').html("<div class='successMessage'>Date range is valid.</div>");
			        }
               } //end of success
            }); //end of ajax
         } //end of if(errors == 0)
      } //end of Submit button function
    } //end of buttons:
}); //end of dialog

Alternate method using javascript (no ajax call) to validate dates:

$('#dialog').dialog({
		autoOpen: false,
		width: 400,
		modal: true,
		resizable: false,
		close: function() {
			$('#message').html("");
			$('#dateRangeForm :input').each(function() {
				$(this).val('');
			});
		 },
		buttons: {
			"Close": function() {
				$(this).dialog("close");
				$('#message').html("");
			     $('#dateRangeForm :input').each(function() {
				$(this).val('');
					 });
			},
			"Submit": function() {
				var errors = 0;

				$('#dateRangeForm :input').each(function() {
					if($(this).val() == ''){
						$(this).prev().prev().css("color", "red");
						$(this).prev().val('Click box and use calendar to enter date.');
						errors++;
					} else {
						$(this).prev().css("color", "black");
					}
				 });

				if (errors == 0){
					var start_date = new Date($("#startdate").val());
					var end_date = new Date($("#enddate").val());
					if(end_date < start_date){
						$('#message').html("<div class='errorMessage'>Date range is invalid.</div>");
					}else{
						$('#message').html("<div class='successMessage'>Date range is valid.</div>");
					}
         } //end of if(errors == 0)
      } //end of Submit button function
   } //end of buttons:
}); //end of dialog

The daterange.php is pretty straightforward:

<?php
$start_date = new DateTime($_POST["startdate"]);
$end_date = new DateTime($_POST["enddate"]);

if ($start_date > $end_date){
    $return_json = '{"error":"invalid"}';
}else{
    $return_json = '{"error":"valid"}';
}

echo $return_json;
?>

Now, it entirely possible that you can validate the dates without a trip to the server; however, this example sets you up to use the dialog datepicker in more advanced processing or database calls on the server.

Recommended:

Demo

Javascript Array to JSON String with JSON.stringify

JSON.stringify is a great little function that I keep forgetting to utilize. It’s here for reference.

var myarray = [];
var myJSON = "";

for (var i = 0; i < 10; i++) {

    var item = {
        "value": i,
        "label": i
    };

    myarray.push(item);
}

myJSON = JSON.stringify({myarray: myarray});

Fiddle

Hit ‘Result’

Generating Barcodes with Barcode Generator and ASP.NET

Generating barcodes in ASP.NET is pretty easy with Barcode Generator. Barcode Generator is free for non-commercial use but priced right for commercial use. If you are a commercial site, try the free version locally and, if it works for you, spring for the license. VB.NET is used below but Barcode Generator’s examples are in C#.

This post modifies the example provided by Barcode Generator only enough so you can put a barcode on a page with a plain img tag as such:

<img src="barcode.aspx?code=hqcfqs55kioevn55saz0me55" alt="barcode" />

barcode example from screenshot
I also got some help from this post by Chris Love: A Quick and Dirty Bar Code Image httpHandler

First, follow the instructions on Barcode Generator’s site to install the dll’s.

Then on barcode.aspx put the following:

Imports System.Web
Imports System.Drawing
Imports System.Drawing.Imaging
Imports BarcodeGenerator

Public Class barcode
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Documentation:
        'http://www.barcodeasp.com/1d/manual.php?ns=BarcodeGenerator&id=BCGBarcode1D
        Dim font As New BCGFont(New Font("Arial", 10, FontStyle.Regular))
        Dim barcode As String

        Dim color_black As New BCGColor(Color.Black)
        Dim color_white As New BCGColor(Color.White)

        If Not IsNothing(Request("code")) AndAlso Len(Request("code").ToString) Then
            barcode = Request("code").ToString
        Else
            barcode = Now.Month.ToString & Now.Day.ToString & Now.Year.ToString
        End If

        Dim code As BCGBarcode1D = New BCGcode39()
        code.setScale(1)
        ' Resolution
        code.setThickness(30)
        ' Thickness
        code.setForegroundColor(color_black)
        ' Color of bars
        code.setBackgroundColor(color_white)
        ' Color of spaces
        code.setFont(font)
        ' Font
        code.parse(barcode)

        Dim drawing As New BCGDrawing(color_white)
        drawing.setBarcode(code)
        drawing.draw()

        Response.ContentType = "image/jpeg"
        ' Save the image into jpeg format.
        drawing.finish(ImageFormat.Jpeg, Response.OutputStream)
    End Sub
End Class

And, that’s it. Set your image tag to the path of your barcode.aspx file with the code as a url param and you’re done.

For JavaScript Disabled: Simple <noscript> Solution

For the 1 – 2% of users that might have JavaScript turned off there is a simple <noscript> css solution. This is somewhat better than a forced redirect which could interfere with search engine optimization.

In the head section, add a <noscript> tag that hides the main content or a section of the main content.

<head>
<!-- head content here -->
<noscript><style type="text/css">#content-container {display: none}</style></noscript>
</head>

In the body of the document, add a container that holds the <noscript> warning:

<noscript>
  <div id="nojs-container" >
    <h1>JavaScript is not enabled</h1>
    <p>Thus application requires <strong>JavaScript</strong>.</p>
    <p>Please see: <a href="http://www.google.com/support/bin/answer.py?answer=23852">How to enable JavaScript</a>.</p>
<!-- you could put a link to a non-javascript page link here instead of the reload link -->
    <p>Once JavaScript is enabled, you can <a href="">load this page again</a>.</p>
  </div>
</noscript>

jQuery UI Autocomplete: Search from Beginning of String

The default functionality of the jQuery UI autocomplete will match text input against any part of a string in a searched data set. If you want to exclusively search from the beginning, you have to make some adjustments.
autocomplete screen shot

Remote Datasource

If you are using a remote datasource that queries a database, you can adjust your SQL statement to match the term at the beginning.

mysql_query("SELECT * FROM states where state like '" . mysql_real_escape_string($_GET['term']) . "%'")

If you cannot adjust the SQL for the remote datasource, you can still search from the start of the string. Be aware that, with this method, you may be returning a large dataset and that could have performance issues.

Using the U.S. states autocomplete as an example (xml source example below), a match can be made from the beginning of the string with a remote datasource like this:

$("#state").autocomplete({
	source: function(req, response) {
	   $.ajax({
		url: "states.php",
		dataType: "json",
		success: function( data ) {
			var re = $.ui.autocomplete.escapeRegex(req.term);
            var matcher = new RegExp( "^" + re, "i" );
			response($.grep(data, function(item){return matcher.test(item.value);}) );
			}
	    });
         },
      minLength: 2,
      select: function(event, ui) {
       $('#state_id').val(ui.item.id);
       $('#abbrev').val(ui.item.abbrev);
       }
});

Several things are happening:

  1. The data from the source is retrieved via an ajax call
  2. The term is escaped for any symbols that may cause a regular expression to be evaluated
  3. The matcher is given a new regular expression that instructs it to begin the search at the start of the string (^) and to be case insensitive (i)
  4. It then calls matcher.test to match the term against the value of the data item (this could be label depending on how your data is returned)

Remember, you need to return either a value or a label in the data item or the autocomplete will not work. Read the autocomplete documentation if you are not familiar with those fields:

The local data can be a simple Array of Strings, or it contains Objects for each item in the array, with either a label or value property or both. The label property is displayed in the suggestion menu. The value will be inserted into the input element after the user selected something from the menu. If just one property is specified, it will be used for both, eg. if you provide only value-properties, the value will also be used as the label.

Remote Datasource Autocomplete Demo

Array Datasource

If the datasource is an array of values or objects, the following method can be applied:

var states = [{"id":"1","label":"Armed Forces Americas (except Canada)","abbrev":"AA"},{"id":"2","label":"Armed Forces Africa, Canada, Europe, Middle East","abbrev":"AE"},{"id":"5","label":"Armed Forces Pacific","abbrev":"AP"},{"id":"9","label":"California","abbrev":"CA"},{"id":"10","label":"Colorado","abbrev":"CO"},{"id":"14","label":"Florida","abbrev":"FL"},{"id":"16","label":"Georgia","abbrev":"GA"},{"id":"33","label":"Northern Mariana Islands","abbrev":"MP"},{"id":"36","label":"North Carolina","abbrev":"NC"},{"id":"37","label":"North Dakota","abbrev":"ND"},{"id":"43","label":"New York","abbrev":"NY"},{"id":"46","label":"Oregon","abbrev":"OR"}];

$("#state").autocomplete({
	source: function(req, response) {
	    var re = $.ui.autocomplete.escapeRegex(req.term);
	    var matcher = new RegExp( "^" + re, "i" );
	    response($.grep(states, function(item){return matcher.test(item.label); }) );
	    },
      minLength: 2,
      select: function(event, ui) {
         $('#state_id').val(ui.item.id);
         $('#abbrev').val(ui.item.abbrev);
     }
});

Similar to the remote datasource example except this does not need the ajax call. The states array is simply pulled into the response and the rest is handled the same.

Array Datasource Autocomplete Demo

XML Source Example