← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 17949: event capture - validating input types on the fly (before hitting submit)

 

------------------------------------------------------------
revno: 17949
committer: Abyot Asalefew Gizaw <abyota@xxxxxxxxx>
branch nick: dhis2
timestamp: Mon 2015-01-12 19:24:10 +0100
message:
  event capture - validating input types on the fly (before hitting submit)
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/defaultForm.html
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html	2014-12-15 14:00:36 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html	2015-01-12 18:24:10 +0000
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
-<html manifest="cacheManifest.action" ng-app="eventCapture">
+<html ng-app="eventCapture">
+<!--<html manifest="cacheManifest.action" ng-app="eventCapture">-->
     <head>
         <title>Event Capture</title>
 
@@ -59,7 +60,7 @@
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.storage.memory.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.storage.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.contextmenu.js"></script>
-        <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.appcache.js"></script>
+        <!--<script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.appcache.js"></script>-->
         <script type="text/javascript" src="../dhis-web-commons/ouwt/ouwt.js"></script>
         <script type="text/javascript" src="scripts/event-capture.js"></script>
         

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js	2014-12-18 11:50:32 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js	2015-01-12 18:24:10 +0000
@@ -137,8 +137,10 @@
                     $scope.eventGridColumns = [];
                     $scope.filterTypes = {};
 
-                    $scope.newDhis2Event = {dataValues: []};
-                    $scope.currentEvent = {dataValues: []};
+                    //$scope.newDhis2Event = {dataValues: []};
+                    //$scope.currentEvent = {dataValues: []};
+                    $scope.currentEvent = {};
+                    $scope.newDhis2Event = {};
 
                     $scope.eventGridColumns.push({name: 'form_id', id: 'uid', type: 'string', compulsory: false, showFilter: false, show: false});
                     $scope.filterTypes['uid'] = 'string';                
@@ -150,7 +152,8 @@
                     angular.forEach($scope.selectedProgramStage.programStageDataElements, function(prStDe){
                         $scope.prStDes[prStDe.dataElement.id] = prStDe;                    
 
-                        $scope.newDhis2Event.dataValues.push({id: prStDe.dataElement.id, value: ''});   
+                        //$scope.newDhis2Event.dataValues.push({id: prStDe.dataElement.id, value: ''});   
+                        $scope.newDhis2Event[prStDe.dataElement.id] = '';
                         if($scope.selectedProgramStage.captureCoordinates){
                             $scope.newDhis2Event.coordinate = {};
                         }
@@ -361,7 +364,8 @@
         $scope.displayCustomForm = $scope.customForm ? true:false;        
         $scope.currentEvent = {};
         $scope.eventRegistration = !$scope.eventRegistration;          
-        $scope.currentEvent = angular.copy($scope.newDhis2Event);        
+        $scope.currentEvent = angular.copy($scope.newDhis2Event);
+        $scope.currentEventOrginialValue = angular.copy($scope.currentEvent);        
         $scope.outerForm.submitted = false;
         $scope.note = {};
         
@@ -373,7 +377,7 @@
     
     $scope.showEditEventInGrid = function(){
         $scope.currentEvent = ContextMenuSelectedItem.getSelectedItem();
-        $scope.currentEventOrginialValue = angular.copy($scope.currentEvent);        
+        $scope.currentEventOrginialValue = angular.copy($scope.currentEvent);
         $scope.editingEventInGrid = !$scope.editingEventInGrid;
         
         $scope.outerForm.$valid = true;
@@ -723,4 +727,16 @@
         }, function () {
         });
     };
+    
+    $scope.formIsChanged = function(){        
+        var isChanged = false;
+        for (var k in $scope.currentEvent) {
+            if ($scope.currentEvent.hasOwnProperty(k)) {
+                if($scope.currentEvent[k] && $scope.currentEventOrginialValue[k] !== $scope.currentEvent[k]){
+                    isChanged = true;
+                }
+            }
+        }
+        return isChanged;
+    };
 });

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/defaultForm.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/defaultForm.html	2014-12-09 23:24:16 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/defaultForm.html	2015-01-12 18:24:10 +0000
@@ -33,7 +33,7 @@
                            ng-required="true" 
                            name="eventDate"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{'date_required'| translate}}</span>
+                    <span ng-show="currentEvent.eventDate && outerForm.eventDate.$invalid || outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{'date_required'| translate}}</span>
                 </td>
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -48,7 +48,7 @@
                            max="90"
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.submitted && outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>
+                    <span ng-show="outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>
                 </td>                                            
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -63,12 +63,12 @@
                            max="180"
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.submitted && outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
+                    <span ng-show="outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
                 </td>                                            
             </tr>
             <!--<span class='pull-right'>
                 <a href ng-click="showMap(currentEvent)" title="{{'get_from_map'| translate}}"><i class="fa fa-map-marker fa-2x"></i></a>
-            </span>-->            
+            </span>-->
             <tr ng-repeat="eventGridColumn in eventGridColumns" ng-if="eventGridColumn.id !== 'comment' && eventGridColumn.id !== 'uid' && eventGridColumn.id !== 'event_date'">
                 <td >
                     {{eventGridColumn.name}}                                    
@@ -78,14 +78,14 @@
                         <div ng-switch="eventGridColumn.type">
                             <div ng-switch-when="int">
                                 <input type="number" 
-                                       d2-validation 
+                                        
                                        d2-number-validation 
                                        number-type={{prStDes[eventGridColumn.id].dataElement.numberType}}
                                        ng-model="currentEvent[eventGridColumn.id]"                                                                
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo" 
                                        style="width:99%;"/>
-                                <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'value_must_be'| translate}} - {{prStDes[eventGridColumn.id].dataElement.numberType | translate}}</span>
+                                <span ng-show="currentEvent[eventGridColumn.id] && innerForm.foo.$invalid" class="required">{{'value_must_be'| translate}} - {{prStDes[eventGridColumn.id].dataElement.numberType | translate}}</span>
                             </div>
                             <div ng-switch-when="string">                                
                                 <div class="container-fluid" ng-if="prStDes[eventGridColumn.id].dataElement.optionSet">
@@ -93,7 +93,7 @@
                                         <input type="text"
                                                class="typeahead"
                                                placeholder="&#xf0d7;&nbsp;&nbsp;" 
-                                               d2-validation 
+                                                
                                                ng-model="currentEvent[eventGridColumn.id]"                                                                    
                                                typeahead="option.name as option.name for option in optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options | filter:$viewValue | limitTo:20" 
                                                typeahead-open-on-focus   
@@ -102,13 +102,13 @@
                                                ng-required={{eventGridColumn.compulsory}}
                                                name="foo" 
                                                style="width:99%;"/>
-                                        <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'option_required'| translate}}</span>
+                                        <span ng-show="innerForm.foo.$invalid" class="required">{{'option_required'| translate}}</span>
                                     </span>                                    
                                     <span ng-if="selectedProgram.dataEntryMethod && optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options.length < 7">                                    
                                         <label>
                                             <input type="radio" 
                                                    name="foo"  
-                                                   d2-validation  
+                                                     
                                                    ng-required={{eventGridColumn.compulsory}}
                                                    ng-model="currentEvent[eventGridColumn.id]"
                                                    value=""> {{'no_value' | translate}}<br>
@@ -116,26 +116,26 @@
                                         <label ng-repeat="option in  optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options">
                                             <input type="radio" 
                                                    name={{eventGridColumn.id}}   
-                                                   d2-validation 
+                                                    
                                                    ng-required={{eventGridColumn.compulsory}}
                                                    ng-model="currentEvent[eventGridColumn.id]"
                                                    value={{option.name}}> {{option.name}}<br>                                        
                                         </label>
-                                        <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
+                                        <span ng-show="innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
                                     </span>
                                 </div>
                                 <div ng-if="!prStDes[eventGridColumn.id].dataElement.optionSet">
                                     <input type="text" 
-                                        d2-validation    
+                                            
                                         ng-model="currentEvent[eventGridColumn.id]"                                        
                                         ng-required={{eventGridColumn.compulsory}}
                                         name="foo" 
                                         style="width:99%;"/>
-                                    <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'string_required'| translate}}</span>
+                                    <span ng-show="innerForm.foo.$invalid" class="required">{{'string_required'| translate}}</span>
                                 </div>                                
                             </div>
                             <div ng-switch-when="bool">
-                                <select d2-validation 
+                                <select  
                                         ng-model="currentEvent[eventGridColumn.id]"                                                                
                                         ng-required={{eventGridColumn.compulsory}}
                                         name="foo" 
@@ -144,27 +144,27 @@
                                 <option value="false">{{'no'| translate}}</option>
                                 <option value="true">{{'yes'| translate}}</option>
                                 </select>
-                                <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'bool_required'| translate}}</span>
+                                <span ng-show="innerForm.foo.$invalid" class="required">{{'bool_required'| translate}}</span>
                             </div>
                             <div ng-switch-when="date">
                                 <input type="text"                                                                
                                        placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                                        d2-date
                                        max-date="prStDes[eventGridColumn.id].allowFutureDate ? '' : 0" 
-                                       d2-validation 
+                                        
                                        ng-model="currentEvent[eventGridColumn.id]"                                                               
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo" 
                                        style="width:99%;"/>
-                                <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
+                                <span ng-show="innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
                             </div>
                             <div ng-switch-when="trueOnly">
                                 <input type="checkbox"          
-                                       d2-validation 
+                                        
                                        ng-model="currentEvent[eventGridColumn.id]"                                                               
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo"/>
-                                <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
+                                <span ng-show="innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
                             </div>
                         </div>
                     </ng-form>                    
@@ -208,7 +208,7 @@
                            ng-required="true" 
                            name="eventDate" 
                            style="width:99%;">
-                    <span ng-show="outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{'date_required'| translate}}</span>
+                    <span ng-show="outerForm.eventDate.$invalid" class="required">{{'date_required'| translate}}</span>
                 </td>
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -223,7 +223,7 @@
                            max="90"
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.submitted && outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>
+                    <span ng-show="outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>
                 </td>                                            
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -238,7 +238,7 @@
                            max="180"
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.submitted && outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
+                    <span ng-show="outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
                 </td>                                            
             </tr>        
         </tbody>
@@ -266,14 +266,14 @@
                                 <div ng-switch="prStDes[de.dataElement.id].dataElement.type">
                                     <div ng-switch-when="int">
                                         <input type="number" 
-                                               d2-validation 
+                                                
                                                d2-number-validation 
                                                number-type={{prStDes[de.dataElement.id].dataElement.numberType}}
                                                ng-model="currentEvent[de.dataElement.id]"                                                                
                                                ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                name="foo" 
                                                style="width:99%;"/>
-                                        <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'value_must_be'| translate}} - {{prStDes[de.dataElement.id].dataElement.numberType | translate}}</span>
+                                        <span ng-show="innerForm.foo.$invalid" class="required">{{'value_must_be'| translate}} - {{prStDes[de.dataElement.id].dataElement.numberType | translate}}</span>
                                     </div>
                                     <div ng-switch-when="string">
                                         <div class="container-fluid" ng-if="prStDes[de.dataElement.id].dataElement.optionSet">                                
@@ -281,7 +281,7 @@
                                                 <input type="text"
                                                        class="typeahead"
                                                        placeholder="&#xf0d7;&nbsp;&nbsp;" 
-                                                       d2-validation 
+                                                        
                                                        ng-model="currentEvent[de.dataElement.id]"                                                                    
                                                        typeahead="option.name as option.name for option in optionSets[prStDes[de.dataElement.id].dataElement.optionSet.id].options | filter:$viewValue | limitTo:20" 
                                                        typeahead-open-on-focus   
@@ -290,13 +290,13 @@
                                                        ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                        name="foo" 
                                                        style="width:99%;"/>
-                                                <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'option_required'| translate}}</span>
+                                                <span ng-show="innerForm.foo.$invalid" class="required">{{'option_required'| translate}}</span>
                                             </span>
                                             <span ng-if="selectedProgram.dataEntryMethod && prStDes[de.dataElement.id].dataElement.optionSet.options.length < 7">                                    
                                                 <label>
                                                     <input type="radio" 
                                                            name="foo" 
-                                                           d2-validation 
+                                                            
                                                            ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                            ng-model="currentEvent[de.dataElement.id]"
                                                            value=""> {{'no_value' | translate}}<br>
@@ -304,26 +304,26 @@
                                                 <label ng-repeat="option in optionSets[prStDes[de.dataElement.id].dataElement.optionSet.id].options">
                                                     <input type="radio" 
                                                            name={{de.dataElement.id}} 
-                                                           d2-validation 
+                                                            
                                                            ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                            ng-model="currentEvent[de.dataElement.id]"
                                                            value={{option.name}}> {{option.name}}<br>                                        
                                                 </label>
-                                                <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
+                                                <span ng-show="innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
                                             </span>
                                         </div>
                                         <div ng-if="!prStDes[de.dataElement.id].dataElement.optionSet">
                                             <input type="text" 
-                                                d2-validation 
+                                                 
                                                 ng-model="currentEvent[de.dataElement.id]"
                                                 ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                 name="foo" 
                                                 style="width:99%;"/>
-                                            <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'string_required'| translate}}</span>
+                                            <span ng-show="innerForm.foo.$invalid" class="required">{{'string_required'| translate}}</span>
                                         </div>
                                     </div>
                                     <div ng-switch-when="bool">
-                                        <select d2-validation 
+                                        <select  
                                                 ng-model="currentEvent[de.dataElement.id]"                                                                
                                                 ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                 name="foo" 
@@ -332,27 +332,27 @@
                                         <option value="false">{{'no'| translate}}</option>
                                         <option value="true">{{'yes'| translate}}</option>
                                         </select>
-                                        <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'bool_required'| translate}}</span>
+                                        <span ng-show="innerForm.foo.$invalid" class="required">{{'bool_required'| translate}}</span>
                                     </div>
                                     <div ng-switch-when="date">
                                         <input type="text"                                                                
                                                placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                                                d2-date
                                                max-date="prStDes[de.dataElement.id].allowFutureDate ? '' : 0" 
-                                               d2-validation 
+                                                
                                                ng-model="currentEvent[de.dataElement.id]"                                                               
                                                ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                name="foo" 
                                                style="width:99%;"/>
-                                        <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
+                                        <span ng-show="innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
                                     </div>
                                     <div ng-switch-when="trueOnly">
                                         <input type="checkbox"       
-                                               d2-validation  
+                                                 
                                                ng-model="currentEvent[de.dataElement.id]"                                                               
                                                ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                name="foo"/>
-                                        <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
+                                        <span ng-show="innerForm.foo.$invalid" class="required">{{'required'| translate}}</span>
                                     </div>
                                 </div>
                             </ng-form>                            
@@ -401,7 +401,7 @@
         <button ng-click="addEvent()" class="button not-printable">{{'save_and_back'| translate}}</button>
         <button ng-click="showEventList(null)" class="button not-printable">{{'go_back'| translate}}</button>        
     </span>
-    <span ng-if="outerForm.submitted && outerForm.$invalid" class="horizontal-spacing red">{{'form_invalid' | translate}}</span>
+    <span ng-if="outerForm.$invalid && formIsChanged()" class="horizontal-spacing red">{{'form_invalid' | translate}}</span>    
     
 </div>
 <!-- buttons for event registration / update ends -->
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js	2015-01-08 17:49:09 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js	2015-01-12 18:24:10 +0000
@@ -4,6 +4,8 @@
 
 var d2Directives = angular.module('d2Directives', [])
 
+
+
 .directive('inputValidator', function() {
     
     return {
@@ -117,19 +119,26 @@
             
             var fieldName = element.attr('name');
             var numberType = attrs.numberType;
+            var isRequired = attrs.ngRequired === 'true';
             
             ctrl.$parsers.unshift(function(value) {
             	if(value){
                     var isValid = checkValidity(numberType, value);
-                	ctrl.$setValidity(fieldName, isValid);
-                	return isValid ? value : undefined;
+                	ctrl.$setValidity(fieldName, isValid);                    
+                	//return isValid ? value : undefined;
+                    return value;
                 }
+                
+                if(value === '' && !isRequired){
+                    ctrl.$setValidity(fieldName, true);                    
+                    return undefined;
+                }                
             });
            
-            ctrl.$formatters.unshift(function(value) {
+            ctrl.$formatters.unshift(function(value) {                
                 if(value){
                     var isValid = checkValidity(numberType, value);
-                    ctrl.$setValidity(fieldName, isValid);
+                    ctrl.$setValidity(fieldName, isValid);                    
                     return value;
                 }
             });
@@ -450,6 +459,8 @@
         require: 'ngModel',        
         link: function(scope, element, attrs, ctrl) {    
             
+            var fieldName = element.attr('name');
+            var isRequired = attrs.ngRequired === 'true';
             var calendarSetting = CalendarService.getSetting();            
             var dateFormat = 'yyyy-mm-dd';
             if(calendarSetting.keyDateFormat === 'dd-MM-yyyy'){
@@ -471,25 +482,32 @@
                 showAnim: "",
                 renderer: $.calendars.picker.themeRollerRenderer,
                 onSelect: function(date) {
-                    $this.change();
+                    $(this).change();
                 }
             })
             .change(function() {
-            	var rawDate = this.value;
-                var convertedDate = DateUtils.format(this.value);
-                
-                var isValid = rawDate == convertedDate;                
-                var fieldName = element.attr('name');
-                
-                if(isValid && maxDate === 0){                    
-                    isValid = !moment(convertedDate, calendarSetting.momentFormat).isAfter(DateUtils.getToday());
-                }
-                
-                ctrl.$setViewValue(isValid ? this.value : undefined);                                   
-                ctrl.$setValidity(fieldName, isValid);
-                
-                this.focus();	            
-	            scope.$apply();
+                if(this.value){
+                    var rawDate = this.value;
+                    var convertedDate = DateUtils.format(this.value);
+
+                    var isValid = rawDate == convertedDate;
+                    
+                    if(isValid && maxDate === 0){                    
+                        isValid = !moment(convertedDate, calendarSetting.momentFormat).isAfter(DateUtils.getToday());
+                    }
+                    
+                    ctrl.$setViewValue(this.value);
+                    ctrl.$setValidity(fieldName, isValid);
+                }
+                else{
+                    if(!isRequired){
+                        ctrl.$setViewValue(this.value);
+                        ctrl.$setValidity(fieldName, !isRequired);                        
+                    }
+                }
+                
+                this.focus();
+                scope.$apply();
             });    
         }      
     };   

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js	2014-12-09 23:24:16 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js	2015-01-12 18:24:10 +0000
@@ -3152,6 +3152,9 @@
       var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
 
       var appendToBody =  attrs.typeaheadAppendToBody ? $parse(attrs.typeaheadAppendToBody) : false;
+      
+      //this is to avoid unnecessarily validating not required inputs for empty value
+      var isRequired = attrs.ngRequired === 'true';
 
       //INTERNAL VARIABLES
 
@@ -3257,9 +3260,16 @@
           return inputValue;
         } else {
           /*modelCtrl.$setValidity('editable', false);
-          return undefined;*/
+          return undefined;*/         
           if(inputValue){ //make sure empty values - though not part of the drop down - are accepted
-            modelCtrl.$setValidity('editable', false);
+          	
+          	if(isRequired){
+          		modelCtrl.$setValidity('editable', false);
+          	}
+          	else{
+          		modelCtrl.$setValidity('editable', true);
+          	}
+            //modelCtrl.$setValidity('editable', false);            
             return undefined;
           }
         }