← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 17686: validation directive - freely typed dates are now validated; empty option is now allowed - for ex...

 

------------------------------------------------------------
revno: 17686
committer: Abyot Asalefew Gizaw <abyota@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2014-12-10 00:24:16 +0100
message:
  validation directive - freely typed dates are now validated; empty option is now allowed - for example to allow users remove previously set values; numbers now respect number value types - positive, negative, integer...
added:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/ec-custom-form.html
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/i18n/i18n_app.properties
  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/scripts/directives.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js
  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/eventList.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js
  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/services.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/i18n/i18n_app.properties'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/i18n/i18n_app.properties	2014-12-08 15:06:43 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/i18n/i18n_app.properties	2014-12-09 23:24:16 +0000
@@ -29,6 +29,7 @@
 go_back=Go back
 form_invalid=Form is invalid. Please check for required fields.
 required=Required
+value_must_be=Value must be
 int_required=Value must be a number
 string_required=Value must be a text
 date_required=Value must be a date
@@ -113,3 +114,9 @@
 update_event=Update Event
 missing_translation_file=Missing Translation File
 missing_translation_using_default=No translation file is found for the selected locale. Using default translation (English).
+number=Number
+posInt=Positive Integer
+negInt=Negative Integer
+zeroPostitiveInt=Zero or Positive Integer
+
+

=== 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-08 15:06:43 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html	2014-12-09 23:24:16 +0000
@@ -33,8 +33,8 @@
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/angular-route.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/angular-cookies.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/angular-animate.js"></script>  
-        <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js"></script>        
-
+        <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/ui-bootstrap-tpls-0.10.0-draggable-modal.js"></script>
+        
         <script type="text/javascript" src="../dhis-web-commons/javascripts/moment/moment-with-langs.min.js"></script>       
 
         <script type="text/javascript" src="../dhis-web-commons/javascripts/underscore.min.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-08 16:37:23 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js	2014-12-09 23:24:16 +0000
@@ -216,21 +216,18 @@
                                             var val = dataValue.value;
                                             if(angular.isObject($scope.prStDes[dataValue.dataElement].dataElement)){                               
 
-                                                //converting int string value to integer for proper sorting.
+                                                //converting int string value to number for proper sorting.
                                                 if($scope.prStDes[dataValue.dataElement].dataElement.type === 'int'){
-                                                    if( !isNaN(parseInt(val)) ){
-                                                        val = parseInt(val);
-                                                    }
-                                                    else{
-                                                        val = '';
-                                                    }                                        
+                                                    if( dhis2.validation.isNumber(val)  ){
+                                                        val = new Number(val);
+                                                    }                                
                                                 }
                                                 if($scope.prStDes[dataValue.dataElement].dataElement.type === 'string'){
                                                     if($scope.prStDes[dataValue.dataElement].dataElement.optionSet &&
                                                             $scope.prStDes[dataValue.dataElement].dataElement.optionSet.id &&
                                                             $scope.optionSets[$scope.prStDes[dataValue.dataElement].dataElement.optionSet.id] &&
                                                             $scope.optionSets[$scope.prStDes[dataValue.dataElement].dataElement.optionSet.id].options ){
-                                                        val = OptionSetService.getNameOrCode($scope.optionSets[$scope.prStDes[dataValue.dataElement].dataElement.optionSet.id].options, val);
+                                                        val = OptionSetService.getName($scope.optionSets[$scope.prStDes[dataValue.dataElement].dataElement.optionSet.id].options, val);
                                                     }                                                
                                                 }
                                                 if($scope.prStDes[dataValue.dataElement].dataElement.type === 'date'){
@@ -428,7 +425,7 @@
                 valueExists = true;            
                 if($scope.prStDes[dataElement].dataElement.type === 'string'){
                     if($scope.prStDes[dataElement].dataElement.optionSet){                        
-                        val = OptionSetService.getNameOrCode($scope.optionSets[$scope.prStDes[dataElement].dataElement.optionSet.id].options,val); //$scope.optionSets[].options$scope.optionCodesByName[  '"' + val + '"'];
+                        val = OptionSetService.getCode($scope.optionSets[$scope.prStDes[dataElement].dataElement.optionSet.id].options,val);
                     }
                 }
 
@@ -545,7 +542,7 @@
             
             if(val && $scope.prStDes[dataElement].dataElement.type === 'string'){
                 if($scope.prStDes[dataElement].dataElement.optionSet){                    
-                    val = OptionSetService.getNameOrCode($scope.optionSets[$scope.prStDes[dataElement].dataElement.optionSet.id].options,val); 
+                    val = OptionSetService.getCode($scope.optionSets[$scope.prStDes[dataElement].dataElement.optionSet.id].options,val); 
                 }    
             }
             if(val && $scope.prStDes[dataElement].dataElement.type === 'date'){
@@ -613,7 +610,7 @@
         var oldValue = $scope.currentEventOrginialValue[dataElement];
         
         //check for form validity
-        $scope.outerForm.submitted = true;        
+        $scope.outerForm.submitted = true;
         if( $scope.outerForm.$invalid ){
             $scope.currentElement.updated = false;
             currentEvent[dataElement] = oldValue;
@@ -630,7 +627,7 @@
             
             if($scope.prStDes[dataElement].dataElement.type === 'string'){
                 if($scope.prStDes[dataElement].dataElement.optionSet){                    
-                    newValue = OptionSetService.getNameOrCode($scope.optionSets[$scope.prStDes[dataElement].dataElement.optionSet.id].options, newValue);//$scope.optionCodesByName[  '"' + newValue + '"'];
+                    newValue = OptionSetService.getCode($scope.optionSets[$scope.prStDes[dataElement].dataElement.optionSet.id].options, newValue);//$scope.optionCodesByName[  '"' + newValue + '"'];
                 }
             }            
             if($scope.prStDes[dataElement].dataElement.type === 'date'){

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/directives.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/directives.js	2014-12-03 17:48:48 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/directives.js	2014-12-09 23:24:16 +0000
@@ -2,5 +2,4 @@
 
 /* Directives */
 
-var eventCaptureDirectives = angular.module('eventCaptureDirectives', []);
-
+var eventCaptureDirectives = angular.module('eventCaptureDirectives', []);
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2014-12-03 17:48:48 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/event-capture.js	2014-12-09 23:24:16 +0000
@@ -436,7 +436,7 @@
 {
     return function() {
         return $.ajax( {
-            url: '../api/programStages.json?filter=id:eq:' + id +'&fields=id,name,version,description,reportDateDescription,captureCoordinates,dataEntryForm,minDaysFromStart,repeatable,preGenerateUID,programStageSections[id,name,programStageDataElements[dataElement[id]]],programStageDataElements[displayInReports,sortOrder,allowProvidedElsewhere,allowFutureDate,compulsory,dataElement[id,name,type,formName,optionSet[id]]]',
+            url: '../api/programStages.json?filter=id:eq:' + id +'&fields=id,name,version,description,reportDateDescription,captureCoordinates,dataEntryForm,minDaysFromStart,repeatable,preGenerateUID,programStageSections[id,name,programStageDataElements[dataElement[id]]],programStageDataElements[displayInReports,sortOrder,allowProvidedElsewhere,allowFutureDate,compulsory,dataElement[id,name,type,numberType,formName,optionSet[id]]]',
             type: 'GET'
         }).done( function( response ){            
             _.each( _.values( response.programStages ), function( programStage ) {                

=== 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-11-19 12:45:44 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/defaultForm.html	2014-12-09 23:24:16 +0000
@@ -56,7 +56,7 @@
                     {{'longitude'| translate}}
                 </td>
                 <td>
-                    <input type="number"
+                    <input type="number"  
                            ng-model="currentEvent.coordinate.longitude"                                                                
                            name="longitude" 
                            min="-180"
@@ -77,19 +77,23 @@
                     <ng-form name="innerForm">
                         <div ng-switch="eventGridColumn.type">
                             <div ng-switch-when="int">
-                                <input type="number"
+                                <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">{{'int_required'| translate}}</span>
+                                <span ng-show="outerForm.submitted && 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">
                                     <span ng-if="!selectedProgram.dataEntryMethod || optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options.length >= 7">
                                         <input type="text"
                                                class="typeahead"
-                                               placeholder="&#xf0d7;&nbsp;&nbsp;"
+                                               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   
@@ -103,7 +107,8 @@
                                     <span ng-if="selectedProgram.dataEntryMethod && optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options.length < 7">                                    
                                         <label>
                                             <input type="radio" 
-                                                   name="foo" 
+                                                   name="foo"  
+                                                   d2-validation  
                                                    ng-required={{eventGridColumn.compulsory}}
                                                    ng-model="currentEvent[eventGridColumn.id]"
                                                    value=""> {{'no_value' | translate}}<br>
@@ -111,6 +116,7 @@
                                         <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>                                        
@@ -119,7 +125,8 @@
                                     </span>
                                 </div>
                                 <div ng-if="!prStDes[eventGridColumn.id].dataElement.optionSet">
-                                    <input type="text"
+                                    <input type="text" 
+                                        d2-validation    
                                         ng-model="currentEvent[eventGridColumn.id]"                                        
                                         ng-required={{eventGridColumn.compulsory}}
                                         name="foo" 
@@ -128,7 +135,8 @@
                                 </div>                                
                             </div>
                             <div ng-switch-when="bool">
-                                <select ng-model="currentEvent[eventGridColumn.id]"                                                                
+                                <select d2-validation 
+                                        ng-model="currentEvent[eventGridColumn.id]"                                                                
                                         ng-required={{eventGridColumn.compulsory}}
                                         name="foo" 
                                         style="width:99%;">
@@ -142,7 +150,8 @@
                                 <input type="text"                                                                
                                        placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                                        d2-date
-                                       max-date="prStDes[eventGridColumn.id].allowFutureDate ? '' : 0"
+                                       max-date="prStDes[eventGridColumn.id].allowFutureDate ? '' : 0" 
+                                       d2-validation 
                                        ng-model="currentEvent[eventGridColumn.id]"                                                               
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo" 
@@ -150,7 +159,8 @@
                                 <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
                             </div>
                             <div ng-switch-when="trueOnly">
-                                <input type="checkbox"                                                                      
+                                <input type="checkbox"          
+                                       d2-validation 
                                        ng-model="currentEvent[eventGridColumn.id]"                                                               
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo"/>
@@ -206,7 +216,7 @@
                     {{'latitude'| translate}}
                 </td>
                 <td>
-                    <input type="number"
+                    <input type="number" 
                            ng-model="currentEvent.coordinate.latitude"                                                                
                            name="latitude"
                            min="-90"
@@ -221,7 +231,7 @@
                     {{'longitude'| translate}}
                 </td>
                 <td>
-                    <input type="number"
+                    <input type="number" 
                            ng-model="currentEvent.coordinate.longitude"                                                                
                            name="longitude" 
                            min="-180"
@@ -255,18 +265,23 @@
                             <ng-form name="innerForm">
                                 <div ng-switch="prStDes[de.dataElement.id].dataElement.type">
                                     <div ng-switch-when="int">
-                                        <input type="number"
+                                        <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%;"/>                                        
+                                               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>
                                     </div>
                                     <div ng-switch-when="string">
                                         <div class="container-fluid" ng-if="prStDes[de.dataElement.id].dataElement.optionSet">                                
                                             <span ng-if="!selectedProgram.dataEntryMethod || optionSets[prStDes[de.dataElement.id].dataElement.optionSet.id].options.length > 8">
                                                 <input type="text"
                                                        class="typeahead"
-                                                       placeholder="&#xf0d7;&nbsp;&nbsp;"
+                                                       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   
@@ -281,13 +296,15 @@
                                                 <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>
                                                 </label>                                    
                                                 <label ng-repeat="option in optionSets[prStDes[de.dataElement.id].dataElement.optionSet.id].options">
                                                     <input type="radio" 
-                                                           name={{de.dataElement.id}}   
+                                                           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>                                        
@@ -296,7 +313,8 @@
                                             </span>
                                         </div>
                                         <div ng-if="!prStDes[de.dataElement.id].dataElement.optionSet">
-                                            <input type="text"
+                                            <input type="text" 
+                                                d2-validation 
                                                 ng-model="currentEvent[de.dataElement.id]"
                                                 ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                 name="foo" 
@@ -305,7 +323,8 @@
                                         </div>
                                     </div>
                                     <div ng-switch-when="bool">
-                                        <select ng-model="currentEvent[de.dataElement.id]"                                                                
+                                        <select d2-validation 
+                                                ng-model="currentEvent[de.dataElement.id]"                                                                
                                                 ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                 name="foo" 
                                                 style="width:99%;">
@@ -319,7 +338,8 @@
                                         <input type="text"                                                                
                                                placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                                                d2-date
-                                               max-date="prStDes[de.dataElement.id].allowFutureDate ? '' : 0"
+                                               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" 
@@ -327,7 +347,8 @@
                                         <span ng-show="outerForm.submitted && innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
                                     </div>
                                     <div ng-switch-when="trueOnly">
-                                        <input type="checkbox"                                                                      
+                                        <input type="checkbox"       
+                                               d2-validation  
                                                ng-model="currentEvent[de.dataElement.id]"                                                               
                                                ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                name="foo"/>

=== added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/ec-custom-form.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/ec-custom-form.html	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/ec-custom-form.html	2014-12-09 23:24:16 +0000
@@ -0,0 +1,98 @@
+<table style='width: 50%;'>
+    <tr ng-if="selectedProgramStage.preGenerateUID">
+        <td>
+            {{'form_id'| translate}}
+        </td>
+        <td>
+            <input type="text" ng-disabled="true" ng-model="currentEvent['uid']" style="width:99%;">
+        </td>
+    </tr>
+    <tr>
+        <td>
+            {{selectedProgramStage.reportDateDescription ? selectedProgramStage.reportDateDescription : 'incident_date'| translate }}
+        </td>
+        <td>
+            <input type="text"                                                   
+                   placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
+                   d2-date
+                   max-date='0'
+                   ng-model="currentEvent.eventDate"
+                   ng-disabled="editingEventInFull"    
+                   ng-required="true" 
+                   name="eventDate"/>
+            <span ng-show="outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{'date_required'| translate}}</span>
+        </td>
+    </tr>
+    <tr ng-if="selectedProgramStage.captureCoordinates">
+        <td>
+            {{'lat_lng' | translate}}
+        </td>
+        <td>
+            <span class="coordinate-container">
+                <input type="number"
+                   ng-model="currentEvent.coordinate.latitude"
+                   placeholder="{{'latitude' | translate}}"    
+                   name="latitude"
+                   min="-90"
+                   max="90"
+                   ng-required="false"
+                   style="min-width:128px"/>
+                <span ng-show="outerForm.submitted && outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>
+            </span>
+            <span class="coordinate-container">
+                <input type="number"
+                   ng-model="currentEvent.coordinate.longitude"                                                                
+                   placeholder="{{'longitude' | translate}}" 
+                   name="longitude" 
+                   min="-180"
+                   max="180"
+                   ng-required="false"
+                   style="min-width:128px"/>
+                <span ng-show="outerForm.submitted && outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
+            </span>
+            <!--<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>-->
+        </td>
+    </tr>
+</table>
+<div ng-include="'../dhis-web-commons/customform/custom-form.html'"></div>  
+<div class="clear">
+    <hr>
+    <h4>
+        {{'comments'| translate}}
+    </h4>
+    <textarea rows="3" ng-model="note.value" placeholder="{{'add_your_comment_here'| translate}}" style="width:50%;"></textarea>
+    <div ng-if="currentEvent.notes">
+        <table class="listTable dhis2-list-table-striped" style='width: 50%;'>
+            <thead>
+                <tr>
+                    <th style="width:100%;">
+                        {{'recorded_comments'| translate}}
+                    </th>
+                </tr>
+            </thead>
+            <tr ng-repeat="note in currentEvent.notes">
+                <td class="over-flow-hidden" style="width:100%;">
+                    <p>{{note.value}}</p>
+                    <p><strong>{{'created_by'| translate}}: </strong>{{note.storedBy}}</p>
+                    <p><strong>{{'date'| translate}}: </strong>{{note.storedDate}}</p>                    
+                </td>
+            </tr>
+        </table>  
+    </div>    
+</div>
+<!-- buttons for event registration / update begins -->
+<div style="clear: both;">                        
+    <span ng-if="editingEventInFull">
+        <button ng-click="updateEvent()" class="button not-printable">{{'update'| translate}}</button>
+        <button ng-click="showEventList()" class="button not-printable">{{'go_back'| translate}}</button>
+    </span>
+    <span ng-if="eventRegistration">
+        <button ng-disabled="disableSaveAndAddNew" ng-click="addEvent(true)" class="button not-printable">{{'save_and_add_new'| translate}}</button>
+        <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>
+</div>
+<!-- buttons for event registration / update ends -->
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/eventList.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/eventList.html	2014-12-04 13:04:31 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/eventList.html	2014-12-09 23:24:16 +0000
@@ -107,9 +107,6 @@
                                         <span ng-if="dhis2Event[eventGridColumn.id] == 'false'">{{'no'| translate}}</span>
                                         <span ng-if="dhis2Event[eventGridColumn.id] == 'true'">{{'yes'| translate}}</span>
                                     </span>
-                                    <!--<span ng-switch-when="date">
-                                        {{dhis2Event[eventGridColumn.id] | date:calendarSetting.keyDateFormat}}
-                                    </span>-->
                                     <span ng-switch-default>
                                         {{dhis2Event[eventGridColumn.id]}}
                                     </span>
@@ -124,21 +121,25 @@
                                 <ng-form name="innerFormGrid">
                                     <div ng-switch="eventGridColumn.type">
                                         <div ng-switch-when="int">
-                                            <input type="number" 
+                                            <input type="text" 
                                                    program-stage-data-element={{prStDes[eventGridColumn.id]}}
+                                                   d2-validation 
+                                                   d2-number-validation
+                                                   number-type={{prStDes[eventGridColumn.id].dataElement.numberType}}
                                                    ng-model="dhis2Event[eventGridColumn.id]" 
                                                    ng-blur="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
                                                    ng-required={{eventGridColumn.compulsory}}
                                                    name="foo" 
                                                    style="width:98%;"
                                                    ng-class="{true: 'update-success'} [currentElement.updated == true && currentElement.id == eventGridColumn.id]"
-                                                   ng-class="{true: 'update-error'} [!currentElement.updated == true && currentElement.id == eventGridColumn.id]"
-                                            />                                                                   
+                                                   ng-class="{true: 'update-error'} [!currentElement.updated == true && currentElement.id == eventGridColumn.id]"/>                                            
                                             <span ng-show="outerForm.submitted && innerFormGrid.foo.$invalid" class="red"><em title="{{'required'| translate}}" class="required">*</em></span>
+                                            <span ng-if="innerFormGrid.foo.$dirty && innerFormGrid.foo.$invalid" class="error">{{'value_must_be'| translate}} - {{prStDes[eventGridColumn.id].dataElement.numberType | translate}}</span>
                                         </div>
                                         <div ng-switch-when="string">                                        
                                             <div ng-if="eventGridColumn.id == 'uid'">
                                                 <input type="text"
+                                                       d2-validation 
                                                        ng-model="currentEvent[eventGridColumn.id]"                                                                    
                                                        ng-disabled=true
                                                        name="foo" 
@@ -148,6 +149,7 @@
                                                 <div class="container-fluid" ng-if="optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id]">                                                
                                                     <span ng-if="!selectedProgram.dataEntryMethod || optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options.length > 7">
                                                         <input type="text" 
+                                                           d2-validation 
                                                            ng-model="dhis2Event[eventGridColumn.id]" 
                                                            ng-blur="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
                                                            typeahead="option.name as option.name for option in optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id].options | filter:$viewValue | limitTo:20" 
@@ -161,11 +163,13 @@
                                                            ng-class="{true: 'update-error'} [!currentElement.updated == true && currentElement.id == eventGridColumn.id]"
                                                            />
                                                         <span ng-show="outerForm.submitted && innerFormGrid.foo.$invalid" class="red"><em title="{{'required'| translate}}" class="required">*</em></span>
+                                                        <span ng-if="innerFormGrid.foo.$dirty && 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" 
+                                                                   name="foo"
+                                                                   d2-validation 
                                                                    ng-required={{eventGridColumn.compulsory}}
                                                                    ng-model="dhis2Event[eventGridColumn.id]" 
                                                                    ng-change="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
@@ -174,6 +178,7 @@
                                                         <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="dhis2Event[eventGridColumn.id]" 
                                                                    ng-change="updateEventDataValue(dhis2Event, eventGridColumn.id)"
@@ -186,6 +191,7 @@
                                                 </div>
                                                 <div ng-if="!optionSets[prStDes[eventGridColumn.id].dataElement.optionSet.id]">
                                                     <input type="text" 
+                                                        d2-validation    
                                                         ng-model="dhis2Event[eventGridColumn.id]" 
                                                         ng-blur="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
                                                         ng-required={{eventGridColumn.compulsory}}
@@ -196,11 +202,13 @@
                                                         ng-class="{true: 'update-error'} [!currentElement.updated == true && currentElement.id == eventGridColumn.id]"
                                                         />
                                                     <span ng-show="outerForm.submitted && innerFormGrid.foo.$invalid" class="red"><em title="{{'required'| translate}}" class="required">*</em></span>
+                                                    <span ng-if="innerFormGrid.foo.$dirty && innerForm.foo.$invalid" class="required">{{'string_required'| translate}}</span>
                                                 </div>
                                             </div>
                                         </div>                                        
                                         <div ng-switch-when="bool">
-                                            <select ng-model="dhis2Event[eventGridColumn.id]" 
+                                            <select d2-validation 
+                                                    ng-model="dhis2Event[eventGridColumn.id]" 
                                                     ng-change="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
                                                     ng-required={{eventGridColumn.compulsory}}
                                                     name="foo" 
@@ -212,12 +220,14 @@
                                                 <option value="true">{{'yes'| translate}}</option>
                                             </select>
                                             <span ng-show="outerForm.submitted && innerFormGrid.foo.$invalid" class="red"><em title="{{'required'| translate}}" class="required">*</em></span>
+                                            <span ng-if="innerFormGrid.foo.$dirty && 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="dhis2Event[eventGridColumn.id]"
                                                    blur-or-change="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
                                                    ng-required={{eventGridColumn.compulsory}}
@@ -228,9 +238,11 @@
                                                    ng-class="{true: 'update-error'} [!currentElement.updated == true && currentElement.id == eventGridColumn.id]"
                                                    />
                                             <span ng-show="outerForm.submitted && innerFormGrid.foo.$invalid" class="red"><em title="{{'required'| translate}}" class="required">*</em></span>
+                                            <span ng-show="innerFormGrid.foo.$dirty && innerForm.foo.$invalid" class="required">{{'date_required'| translate}}</span>
                                         </div>
                                         <div ng-switch-when="trueOnly">
                                             <input type="checkbox"
+                                                   d2-validation 
                                                    ng-model="dhis2Event[eventGridColumn.id]"
                                                    ng-change="updateEventDataValue(dhis2Event, eventGridColumn.id)" 
                                                    ng-required={{eventGridColumn.compulsory}}

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/dashboard/dashboard-controller.js	2014-12-09 23:24:16 +0000
@@ -62,16 +62,10 @@
                         }
                     });
                     
-                    $scope.optionSets = {optionSets: [], optionNamesByCode: new Object(), optionCodesByName: new Object()};
+                    $scope.optionSets = [];
                     OptionSetService.getAll().then(function(optionSets){
-                        angular.forEach(optionSets, function(optionSet){
-                            angular.forEach(optionSet.options, function(option){
-                                if(option.name && option.code){
-                                    $scope.optionSets.optionNamesByCode[ '"' + option.code + '"'] = option.name;
-                                    $scope.optionSets.optionCodesByName[ '"' + option.name + '"'] = option.code;
-                                }                       
-                            });
-                            $scope.optionSets.optionSets[optionSet.id] = optionSet;
+                        angular.forEach(optionSets, function(optionSet){                            
+                            $scope.optionSets[optionSet.id] = optionSet;
                         });
                         
                         //broadcast selected items for dashboard controllers

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/notes/notes-controller.js	2014-12-09 23:24:16 +0000
@@ -9,7 +9,7 @@
     
     var loginDetails = storage.get('LOGIN_DETAILS');
     var storedBy = '';
-    if(loginDetails){
+    if(loginDetails && loginDetails.userCredentials){
         storedBy = loginDetails.userCredentials.username;
     }
     

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html	2014-12-09 23:24:16 +0000
@@ -76,7 +76,7 @@
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/angularjs-nvd3-directives.min.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/angularLocalStorage.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/angular-translate.min.js"></script>
-        <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js"></script>
+        <!--<script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js"></script>-->
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/dhis2/filters.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/dhis2/services.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/angular/plugins/dhis2/controllers.js"></script>

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/app.js	2014-12-09 23:24:16 +0000
@@ -12,7 +12,6 @@
          'trackerCaptureDirectives', 
          'trackerCaptureControllers',
          'd2Filters',
-         'd2Directives',
          'd2Services',
          'd2Controllers',
          'angularLocalStorage',

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/directives.js	2014-12-09 23:24:16 +0000
@@ -2,9 +2,9 @@
 
 /* Directives */
 
-var trackerCaptureDirectives = angular.module('trackerCaptureDirectives', []);
+var trackerCaptureDirectives = angular.module('trackerCaptureDirectives', [])
 
-/*.directive('inputValidator', function() {
+.directive('inputValidator', function() {
     
     return {
         require: 'ngModel',
@@ -16,19 +16,34 @@
         }
     };   
 })
-.directive('selectedOrgUnit', function(storage) {
+
+.directive('selectedOrgUnit', function($timeout, storage) {        
+
     return {        
         restrict: 'A',        
-        link: function(scope, element, attrs){  
-           
+        link: function(scope, element, attrs){
+            
+            //once ou tree is loaded, start meta-data download
+            $(function() {
+                dhis2.ou.store.open().done( function() {
+                    selection.load();
+                    $( "#orgUnitTree" ).one( "ouwtLoaded", function(event, ids, names) {
+                        console.log('Finished loading orgunit tree');                        
+                        downloadMetaData();
+                    });
+                });
+            });
+            
             //listen to user selection, and inform angular         
-            selection.setListenerFunction( organisationUnitSelected, true );
-            selection.responseReceived();
+            selection.setListenerFunction( setSelectedOu, true );
             
-            function organisationUnitSelected( orgUnits, orgUnitNames ) {                
-                scope.selectedOrgUnit = {id: orgUnits[0], name: orgUnitNames[0]};
-                scope.$apply();
-            }            
+            function setSelectedOu( ids, names ) {
+                var ou = {id: ids[0], name: names[0]};
+                $timeout(function() {
+                    scope.selectedOrgUnit = ou;
+                    scope.$apply();
+                });
+            }
         }  
     };
 })
@@ -172,8 +187,12 @@
                 
                 var rawDate = this.value;
                 var convertedDate = DateUtils.format(this.value);
+                
+                console.log('raw date:  ', rawDate);
+                console.log('cnv date:  ', convertedDate);
 
                 if(rawDate != convertedDate){
+                    console.log('It is invalid...');
                     scope.invalidDate = true;
                     ctrl.$setViewValue(this.value);                                   
                     ctrl.$setValidity('foo', false);                    
@@ -204,6 +223,22 @@
     };
 })
 
+.directive('d2TypeaheadValidation', function() {
+    
+    return {
+        require: 'ngModel',
+        restrict: 'A',
+        link: function (scope, element, attrs, ctrl) {
+            element.bind('blur', function () {                
+                if(ctrl.$viewValue && !ctrl.$modelValue){
+                    ctrl.$setViewValue();
+                    ctrl.$render();
+                }                
+            });
+        }
+    };
+})
+
 .directive('typeaheadOpenOnFocus', function ($compile) {
   return {
     require: ['typeahead', 'ngModel'],
@@ -220,7 +255,15 @@
   };
 })
 
-
+.directive('serversidePaginator', function factory() {
+    return {
+        restrict: 'E',
+        controller: function ($scope, Paginator) {
+            $scope.paginator = Paginator;
+        },
+        templateUrl: '../dhis-web-commons/paging/serverside-pagination.html'
+    };
+})
 
 .directive('d2Enter', function () {
     return function (scope, element, attrs) {
@@ -233,4 +276,4 @@
             }
         });
     };
-})*/
\ No newline at end of file
+});
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/services.js	2014-12-09 23:24:16 +0000
@@ -4,7 +4,6 @@
 
 var trackerCaptureServices = angular.module('trackerCaptureServices', ['ngResource'])
 
-
 .factory('StorageService', function(){
     var store = new dhis2.storage.Store({
         name: "dhis2tc",
@@ -457,19 +456,16 @@
             return def.promise();            
         },
         showRequiredAttributes: function(requiredAttributes, teiAttributes, fromEnrollment, optionSets){        
+            
+            console.log('required attribtues:  ', requiredAttributes);
+            console.log('tei attribtue:  ', teiAttributes);
             //first reset teiAttributes
             for(var j=0; j<teiAttributes.length; j++){
-                teiAttributes[j].show = false;
+                teiAttributes[j].show = false;                
                 if(teiAttributes[j].value){                    
                     if(teiAttributes[j].type === 'number' && !isNaN(parseInt(teiAttributes[j].value))){
                         teiAttributes[j].value = parseInt(teiAttributes[j].value);                        
-                    }
-                    /*if(teiAttributes[j].type === 'date'){
-                        teiAttributes[j].value = DateUtils.formatFromApiToUser(teiAttributes[j].value);                        
-                    }*/
-                    if(teiAttributes[j].type === 'optionSet' && optionSets.optionNamesByCode[ '"' + teiAttributes[j].value + '"']){
-                        teiAttributes[j].value = optionSets.optionNamesByCode[ '"' + teiAttributes[j].value + '"'];
-                    }
+                    }                    
                 }               
             }
 
@@ -995,5 +991,95 @@
             return e;
         }
     }; 
+})
+
+/* service for getting calendar setting */
+.service('CalendarService', function(storage, $rootScope){    
+
+    return {
+        getSetting: function() {
+            
+            var dhis2CalendarFormat = {keyDateFormat: 'yyyy-MM-dd', keyCalendar: 'gregorian', momentFormat: 'YYYY-MM-DD'};                
+            var storedFormat = storage.get('CALENDAR_SETTING');
+            if(angular.isObject(storedFormat) && storedFormat.keyDateFormat && storedFormat.keyCalendar){
+                if(storedFormat.keyCalendar === 'iso8601'){
+                    storedFormat.keyCalendar = 'gregorian';
+                }
+
+                if(storedFormat.keyDateFormat === 'dd-MM-yyyy'){
+                    dhis2CalendarFormat.momentFormat = 'DD-MM-YYYY';
+                }
+                
+                dhis2CalendarFormat.keyCalendar = storedFormat.keyCalendar;
+                dhis2CalendarFormat.keyDateFormat = storedFormat.keyDateFormat;
+            }
+            $rootScope.dhis2CalendarFormat = dhis2CalendarFormat;
+            return dhis2CalendarFormat;
+        }
+    };            
+})
+
+/* service for dealing with dates */
+.service('DateUtils', function($filter, CalendarService){
+    
+    return {        
+        getDate: function(dateValue){
+            if(!dateValue){
+                return;
+            }            
+            var calendarSetting = CalendarService.getSetting();
+            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
+            return Date.parse(dateValue);
+        },
+        format: function(dateValue) {            
+            if(!dateValue){
+                return;
+            }
+            
+            if( isNaN( Date.parse(dateValue) ) ){
+                return;
+            }
+            var calendarSetting = CalendarService.getSetting();            
+            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
+            dateValue = $filter('date')(dateValue, calendarSetting.keyDateFormat);            
+            return dateValue;
+        },
+        formatToHrsMins: function(dateValue) {
+            var calendarSetting = CalendarService.getSetting();
+            var dateFormat = 'YYYY-MM-DD @ hh:mm A';
+            if(calendarSetting.keyDateFormat === 'dd-MM-yyyy'){
+                dateFormat = 'DD-MM-YYYY @ hh:mm A';
+            }            
+            return moment(dateValue).format(dateFormat);
+        },
+        getToday: function(){  
+            var calendarSetting = CalendarService.getSetting();
+            var tdy = $.calendars.instance(calendarSetting.keyCalendar).newDate();            
+            var today = moment(tdy._year + '-' + tdy._month + '-' + tdy._day, 'YYYY-MM-DD')._d;            
+            today = Date.parse(today);     
+            today = $filter('date')(today,  calendarSetting.keyDateFormat);
+            return today;
+        },
+        formatFromUserToApi: function(dateValue){            
+            if(!dateValue){
+                return;
+            }
+            var calendarSetting = CalendarService.getSetting();
+            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
+            dateValue = Date.parse(dateValue);     
+            dateValue = $filter('date')(dateValue, 'yyyy-MM-dd'); 
+            return dateValue;            
+        },
+        formatFromApiToUser: function(dateValue){            
+            if(!dateValue){
+                return;
+            }            
+            var calendarSetting = CalendarService.getSetting();
+            dateValue = moment(dateValue, 'YYYY-MM-DD')._d;
+            dateValue = Date.parse(dateValue);     
+            dateValue = $filter('date')(dateValue, calendarSetting.keyDateFormat); 
+            return dateValue;
+        }
+    };
 });
 

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-12-08 15:56:07 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tracker-capture.js	2014-12-09 23:24:16 +0000
@@ -509,7 +509,7 @@
         return $.ajax( {
             url: '../api/programStages.json',
             type: 'GET',
-            data: 'filter=id:eq:' + id +'&fields=id,name,version,dataEntryForm,captureCoordinates,blockEntryForm,autoGenerateEvent,openAfterEnrollment,reportDateToUse,reportDateDescription,minDaysFromStart,standardInterval,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowFutureDate,compulsory,dataElement[id,name,formName,type,optionSet[id]]]'
+            data: 'filter=id:eq:' + id +'&fields=id,name,version,dataEntryForm,captureCoordinates,blockEntryForm,autoGenerateEvent,openAfterEnrollment,reportDateToUse,reportDateDescription,minDaysFromStart,standardInterval,repeatable,programStageDataElements[displayInReports,allowProvidedElsewhere,allowFutureDate,compulsory,dataElement[id,name,formName,type,numberType,optionSet[id]]]'
         }).done( function( response ){            
             _.each( _.values( response.programStages ), function( programStage ) {
                 dhis2.tc.store.set( 'programStages', programStage );

=== 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	2014-12-08 16:37:23 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/directives.js	2014-12-09 23:24:16 +0000
@@ -62,17 +62,52 @@
     };
 })
 
-.directive('d2TypeaheadValidation', function() {
+.directive('d2NumberValidation', function() {
     
     return {
         require: 'ngModel',
         restrict: 'A',
         link: function (scope, element, attrs, ctrl) {
-            element.bind('blur', function () {                
-                if(ctrl.$viewValue && !ctrl.$modelValue){
-                    ctrl.$setViewValue();
-                    ctrl.$render();
-                }                
+            
+            function checkValidity(numberType, value){
+                var isValid = false;
+                switch(numberType){
+                    case "number":
+                        isValid = dhis2.validation.isNumber(value);
+                        break;
+                    case "posInt":
+                        isValid = dhis2.validation.isPositiveInt(value);
+                        break;
+                    case "negInt":
+                        isValid = dhis2.validation.isNegativeInt(value);
+                        break;
+                    case "zeroPostitiveInt":
+                        isValid = dhis2.validation.isZeroOrPositiveInt(value);
+                        break;
+                    case "int":
+                        isValid = dhis2.validation.isInt(value);
+                        break;
+                    default:
+                        isValid = true;
+                }
+                return isValid;
+            }
+            
+            var fieldName = element.attr('name');
+            var numberType = attrs.numberType;
+            
+            ctrl.$parsers.unshift(function(value) {
+                var isValid = checkValidity(numberType, value);
+                ctrl.$setValidity(fieldName, isValid);
+                return isValid ? value : undefined;
+            });            
+           
+            ctrl.$formatters.unshift(function(value) {
+                if(value){
+                    var isValid = checkValidity(numberType, value);
+                    ctrl.$setValidity(fieldName, isValid);
+                    return value;
+                }
             });
         }
     };
@@ -95,6 +130,22 @@
     };
 })
 
+.directive('d2TypeaheadValidation', function() {
+    
+    return {
+        require: 'ngModel',
+        restrict: 'A',
+        link: function (scope, element, attrs, ctrl) {
+            element.bind('blur', function () {                
+                if(ctrl.$viewValue && !ctrl.$modelValue){
+                    ctrl.$setViewValue();
+                    ctrl.$render();
+                }                
+            });
+        }
+    };
+})
+
 .directive('d2PopOver', function($compile, $templateCache){
     return {        
         restrict: 'EA',
@@ -392,28 +443,21 @@
                 showAnim: "",
                 renderer: $.calendars.picker.themeRollerRenderer,
                 onSelect: function(date) {
-                    //scope.date = date;
                     ctrl.$setViewValue(date);
                     $(this).change();                    
                     scope.$apply();
                 }
             })
-            .change(function() {                
-                var rawDate = this.value;
+            .change(function() {
+            	var rawDate = this.value;
                 var convertedDate = DateUtils.format(this.value);
-
-                if(rawDate != convertedDate){
-                    scope.invalidDate = true;
-                    ctrl.$setViewValue(this.value);                                   
-                    ctrl.$setValidity('foo', false);                    
-                    scope.$apply();     
-                }
-                else{
-                    scope.invalidDate = false;
-                    ctrl.$setViewValue(this.value);                                   
-                    ctrl.$setValidity('foo', true);                    
-                    scope.$apply();     
-                }
+                
+                var isValid = rawDate == convertedDate;                
+                var fieldName = element.attr('name');
+                
+                ctrl.$setViewValue(isValid ? this.value : undefined);                                   
+                ctrl.$setValidity(fieldName, isValid);	            
+	            scope.$apply();
             });    
         }      
     };   

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js	2014-12-08 16:37:23 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/dhis2/services.js	2014-12-09 23:24:16 +0000
@@ -63,8 +63,7 @@
                 });
             });                        
             return def.promise;            
-        },
-        
+        },        
         getCode: function(options, key){
             if(options){
                 for(var i=0; i<options.length; i++){
@@ -74,8 +73,7 @@
                 }
             }            
             return key;
-        },
-        
+        },        
         getName: function(options, key){
             if(options){
                 for(var i=0; i<options.length; i++){                    
@@ -214,8 +212,13 @@
         format: function(dateValue) {            
             if(!dateValue){
                 return;
-            }            
-            var calendarSetting = CalendarService.getSetting();
+            }
+            
+            if( isNaN( Date.parse(dateValue) ) ){
+                return;
+            }
+            var calendarSetting = CalendarService.getSetting();            
+            dateValue = moment(dateValue, calendarSetting.momentFormat)._d;
             dateValue = $filter('date')(dateValue, calendarSetting.keyDateFormat);            
             return dateValue;
         },
@@ -306,15 +309,19 @@
                         if(programStageDataElements[deId].dataElement.type == "int"){
                             newInputField = '<input type="number" ' +
                                             this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
+                                            ' d2-number-validation ' +
+                                            ' number-type="' + programStageDataElements[deId].dataElement.numberType + '" ' +
                                             ' ng-model="currentEvent.' + deId + '"' +
                                             ' ng-required="prStDes.' + deId + '.compulsory"> ' + 
-                                            '<span ng-show="outerForm.submitted && outerForm.'+ deId +'.$invalid" class="required">{{\'int_required\'| translate}}</span>';                                     
+                                            '<span ng-show="outerForm.submitted && outerForm.'+ deId +'.$invalid" class="required">{{\'value_must_be\'| translate}} - {{ "' + programStageDataElements[deId].dataElement.numberType + '" | translate}}</span>';                                     
                         }
                         if(programStageDataElements[deId].dataElement.type == "string"){
                             if(programStageDataElements[deId].dataElement.optionSet){
                                 var optionSetId = programStageDataElements[deId].dataElement.optionSet.id;
                         		newInputField = '<input type="text" ' +
                                             this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
                                             ' ng-model="currentEvent.' + deId + '" ' +
                                             ' ng-disabled="currentEvent[uid] == \'uid\'" ' +
                                             ' ng-required="prStDes.' + deId + '.compulsory"' +
@@ -329,6 +336,7 @@
                         	else{
                         		newInputField = '<input type="text" ' +
                                             this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
                                             ' ng-model="currentEvent.' + deId + '" ' +
                                             ' ng-disabled="currentEvent[uid] == \'uid\'" ' +
                                             ' ng-required="prStDes.' + deId + '.compulsory"> ' +
@@ -338,6 +346,7 @@
                         if(programStageDataElements[deId].dataElement.type == "bool"){
                             newInputField = '<select ' +
                                             this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
                                             ' ng-model="currentEvent.' + deId + '" ' +
                                             ' ng-required="prStDes.' + deId + '.compulsory">' + 
                                             '<option value="">{{\'please_select\'| translate}}</option>' +
@@ -349,6 +358,7 @@
                         if(programStageDataElements[deId].dataElement.type == "date"){
                             newInputField = '<input type="text" ' +
                                             this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
                                             ' ng-model="currentEvent.' + deId + '"' +
                                             ' d2-date ' +
                                             ' max-date="' + maxDate + '"' + '\'' +
@@ -358,6 +368,7 @@
                         if(programStageDataElements[deId].dataElement.type == "trueOnly"){
                             newInputField = '<input type="checkbox" ' +
                                             this.getAttributesAsString(attributes) +
+                                            ' d2-validation ' +
                                             ' ng-model="currentEvent.' + deId + '"' +
                                             ' ng-required="prStDes.' + deId + '.compulsory"> ' +
                                             '<span ng-show="outerForm.submitted && outerForm.'+ deId +'.$invalid" class="required">{{\'required\'| translate}}</span>';

=== 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-10-20 16:24:09 +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	2014-12-09 23:24:16 +0000
@@ -3256,8 +3256,12 @@
         if (isEditable) {
           return inputValue;
         } else {
-          modelCtrl.$setValidity('editable', false);
-          return undefined;
+          /*modelCtrl.$setValidity('editable', false);
+          return undefined;*/
+          if(inputValue){ //make sure empty values - though not part of the drop down - are accepted
+            modelCtrl.$setValidity('editable', false);
+            return undefined;
+          }
         }
       });