9/20/15

AngularJS HTML5 Date Range Controller


When dealing with date input fields, we often rely on the use of JavaScripts date pickers to control how the user can enter the data.  These date pickers in most cases take away from the native experience especially on mobile devices.  

With the support of HTML5 in modern devices, we could eliminate the use of JavaScript date pickers and instead make use of the native date type support (more information here).  As an example,  Let’s take a look at how we can build a date range simple app with AngularJS and HTML5. 


Widget:





In this implementation of a date range app, we bind our dateRange model properties (startDate, endDate) to two input fields (from,to). The idea is that based on the start date selection, we define the constraints for our end date. In this example, our constraints are set to a future date and no more than seven days.

To enable the native date picker control, we set both input fields to “type=date”. This enables the device to render a native control for the date selection as well as the limit on what can be typed in the control.

As we change the start date, the on-change event is raised.  In the handler for this event, we set the min and max HTML5 properties which help us on set the edge input constraints for the end date field. In our case, we set the min to one day more than the start date and max to seven days more.  This is done by binding the model properties (minDate,maxDate) to the input field properties (min,max) respectively. We should also note that we must use the ISO date format (yyyy-MM-dd) otherwise our constraints would not be enforced.


The result of settings these edge constraints are reflected on the date picker as only the dates with-in the constraints are enabled. All other dates are disabled (grayed-out) and can’t be selected.



As devices adapt the HTML5 standards, our apps can leverage their native support which enables our apps with a much better user experience.

Thanks for reading.

9/12/15

AngularJS Autocomplete Directive with Label and Value Model Properties

With AngularJS, we can use the JQuery UI Autocomplete widget (details here) to convert any text box to an autocomplete control which can either call a web service or use an object array as data source.  The limitation with this widget is that it only knows of the one control associated to the directive which means that we can only set either the label or value.

To illustrate this limitation, let’s look at a simple customer search with autocomplete implementation in which we just type names starting with the letter O.







Problem Description:

As we type the client information, we can see that the widget automatically shows a list of names matching what has been entered. When a name is selected from the list, it is assigned to the autocomplete text box which is bound to a model property (client.name), but for more practical purposes, we would also like to get the id.  We can also note the header label only shows the information that was typed, but not the selected name. There is also a problem with updating the view.

Solution:

Since for most common cases we need the behavior to be similar to a Select control which has both a Label and Option value properties, we need to add a hidden input field and set the ng-model attribute to the model property, client.id. We are now set to capture the client name and id in two different fields. The problem still remains that we need to extend the autocomplete functionality, so that we are able to set the client.id property on the form.

To address this challenge in a simple approach, we can add a callback on the controller scope which can be used by the directive to callback and set any additional properties.  Let’s take a look at a simple implementation of this approach:




The controller has a new scope function (setCliendData) which is available to the directive via the injected scope variable.  This function just sets the controller model with the selected option. The change on the directive is to implement the select event handler which is raised after every selection from the list. We should note that we need to call the controller function using scope.$apply to force a digest cycle which updates the view with the new model value.  If this is not done, the view would not get updated, and our header would not display the client id and name properly.

What to Note:

The autocomplete widget by default uses the properties value or label to build the list. If those properties are not found, a list with empty names is displayed. To address this, on the directive autocomplete source handler, we map the name property to the value (or label) property that is expected by the autocomplete widget.

We should note that this approach works by sharing the controller scope with the directive. When using isolated scope on the directive, the calls to the dataSource and setCliendData would not be available on the directive, and this would need to be implemented differently.  


I hope this provides some help on how to address some of the limitations when building autocomplete functionality on your apps.