← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19174: event-capture: refactored messaging and validation directives

 

------------------------------------------------------------
revno: 19174
committer: Abyot Asalefew Gizaw <abyota@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2015-05-22 12:23:04 +0200
message:
  event-capture: refactored messaging and validation directives
removed:
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/coordinatecapture/
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/coordinatecapture/map.html
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/customform/
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/customform/custom-form.html
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-static-files.min.js
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-url.min.js
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/paging/serverside-pagination.html
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/event-capture.appcache
  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/app.js
  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/styles/style.css
  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/ec-custom-form.html


--
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/event-capture.appcache'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/event-capture.appcache	2015-03-27 15:20:49 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/event-capture.appcache	2015-05-22 10:23:04 +0000
@@ -68,6 +68,7 @@
 ../dhis-web-commons/javascripts/angular/plugins/angularLocalStorage.js
 ../dhis-web-commons/javascripts/angular/plugins/angular-translate.min.js
 ../dhis-web-commons/javascripts/dhis2/dhis2.angular.directives.js
+../dhis-web-commons/javascripts/dhis2/dhis2.angular.validations.js
 ../dhis-web-commons/javascripts/dhis2/dhis2.angular.filters.js
 ../dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js
 ../dhis-web-commons/javascripts/dhis2/dhis2.angular.controllers.js
@@ -105,9 +106,10 @@
 ../icons/function-log-out.png
 ../icons/function-about-dhis2.png
 
-../dhis-web-commons/paging/serverside-pagination.html
-../dhis-web-commons/customform/custom-form.html
-../dhis-web-commons/coordinatecapture/map.html
+../dhis-web-commons/angular-forms/serverside-pagination.html
+../dhis-web-commons/angular-forms/custom-form.html
+../dhis-web-commons/angular-forms/map.html
+../dhis-web-commons/angular-forms/error-messages.html
 
 
 views/column-modal.html

=== 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	2015-04-30 11:28:47 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/i18n/i18n_app.properties	2015-05-22 10:23:04 +0000
@@ -31,7 +31,7 @@
 required=Required
 int_required=Value must be a number
 string_required=Value must be a text
-date_required=Value must be a date
+date_required=Value must be date
 option_required=Value must be selected from drop-down
 bool_required=Value must be a boolean
 ok=Ok
@@ -129,6 +129,8 @@
 posInt=Positive Integer
 negInt=Negative Integer
 zeroPositiveInt=Zero or Positive Integer
+latitude_required=Value must be between [-90 ... 90]
+longitude_required=Value must be between [-180 ... 180]
 loading_tree=Loading orgunit tree
 loading_metadata=Loading meta-data
 future_date_not_allowed=Future date is not allowed

=== 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	2015-05-08 19:23:53 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/index.html	2015-05-22 10:23:04 +0000
@@ -41,7 +41,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/angular-messages.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>       
 
@@ -74,6 +75,7 @@
         <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/dhis2/dhis2.angular.directives.js"></script>
+        <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.validations.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.filters.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.services.js"></script>
         <script type="text/javascript" src="../dhis-web-commons/javascripts/dhis2/dhis2.angular.controllers.js"></script>

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/app.js	2015-01-28 19:03:29 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/app.js	2015-05-22 10:23:04 +0000
@@ -3,33 +3,35 @@
 /* App Module */
 
 var eventCapture = angular.module('eventCapture',
-		 ['ui.bootstrap', 
-		  'ngRoute', 
-		  'ngCookies', 
-		  'eventCaptureDirectives', 
-		  'eventCaptureControllers', 
-		  'eventCaptureServices',
-          'eventCaptureFilters',
-		  'd2Filters',
-          'd2Directives',
-          'd2Services',
-          'd2Controllers',
-		  'angularLocalStorage', 
-		  'pascalprecht.translate',
-          'd2HeaderBar'])
-              
+                    ['ui.bootstrap',
+                    'ngRoute',
+                    'ngCookies',
+                    'ngMessages',
+                    'eventCaptureDirectives',
+                    'eventCaptureControllers',
+                    'eventCaptureServices',
+                    'eventCaptureFilters',
+                    'd2Filters',
+                    'd2Directives',
+                    'd2Services',
+                    'd2Controllers',
+                    'angularLocalStorage',
+                    'pascalprecht.translate',
+                    'd2HeaderBar'])
+
 .value('DHIS2URL', '..')
 
-.config(function($routeProvider, $translateProvider) {    
-    
+.config(function ($routeProvider, $translateProvider) {
+
     $routeProvider.when('/', {
         templateUrl: 'views/home.html',
         controller: 'MainController'
     }).otherwise({
-        redirectTo : '/'
+        redirectTo: '/'
     });
-    
+
     $translateProvider.preferredLanguage('en');
+    $translateProvider.useSanitizeValueStrategy('escaped');
     $translateProvider.useLoader('i18nLoader');
-    
+
 });
\ No newline at end of file

=== 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	2015-05-07 08:21:29 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/scripts/controllers.js	2015-05-22 10:23:04 +0000
@@ -10,7 +10,6 @@
         function($scope,
                 $modal,
                 $timeout,
-                $translate,
                 $anchorScroll,
                 orderByFilter,
                 SessionStorageService,
@@ -27,7 +26,6 @@
                 GridColumnService,
                 CustomFormService,
                 ECStorageService,
-                ErrorMessageService,
                 CurrentSelection,
                 ModalService,
                 DialogService,
@@ -162,19 +160,19 @@
                 $scope.filterTypes['event_date'] = 'date';
                 $scope.filterText['event_date']= {};
 
-                var errorMessages = {};
-                errorMessages['eventDate'] = $translate('required');
+                //var errorMessages = {};
+                //errorMessages['eventDate'] = $translate('required');
                 angular.forEach($scope.selectedProgramStage.programStageDataElements, function(prStDe){
                     $scope.prStDes[prStDe.dataElement.id] = prStDe;
 
-                    errorMessages[prStDe.dataElement.id] = "";
+                    /*errorMessages[prStDe.dataElement.id] = "";
                     if(prStDe.compulsory){
                         var msg = $translate('required');
                         if(prStDe.dataElement.type === 'int'){
                             msg = $translate(prStDe.dataElement.numberType)+ ' ' + $translate('required');
                         }
                         errorMessages[prStDe.dataElement.id] = msg;
-                    }
+                    }*/
 
                     $scope.newDhis2Event[prStDe.dataElement.id] = '';                    
 
@@ -202,8 +200,6 @@
                 }
                 $scope.newDhis2Event.eventDate = '';
 
-                ErrorMessageService.setErrorMessages(errorMessages);
-
                 ProgramValidationService.getByProgram($scope.selectedProgram.id).then(function(pvs){
                     $scope.programValidations = pvs;
                     $scope.loadEvents();
@@ -794,7 +790,7 @@
     
     $scope.showMap = function(event){
         var modalInstance = $modal.open({
-            templateUrl: '../dhis-web-commons/coordinatecapture/map.html',
+            templateUrl: '../dhis-web-commons/angular-forms/map.html',
             controller: 'MapController',
             windowClass: 'modal-full-window',
             resolve: {
@@ -831,6 +827,7 @@
     };
     
     $scope.isFormInvalid = function(){
+        
         if($scope.outerForm.submitted){
             return $scope.outerForm.$invalid;
         }
@@ -857,11 +854,7 @@
         
         return formIsInvalid;
     };
-    
-    $scope.getErrorMessage = function(id){
-        return ErrorMessageService.get(id);
-    };
-    
+
     $scope.formHasUnsavedData = function(){        
         if(angular.isObject($scope.currentEvent) && angular.isObject($scope.currentEventOriginialValue)){
             return !angular.equals($scope.currentEvent, $scope.currentEventOriginialValue);
@@ -880,4 +873,11 @@
             $( "#orgUnitTree" ).removeClass( "disable-clicks" );
         }
     });
+    
+    $scope.interacted = function(field) {
+        if(field){
+            return $scope.outerForm.submitted || field.$dirty;
+        }        
+        return false;        
+    };
 });
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/styles/style.css'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/styles/style.css	2015-04-20 11:29:12 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/styles/style.css	2015-05-22 10:23:04 +0000
@@ -908,21 +908,21 @@
 }
 
 .map_context_menu{
-	background-color:white;
-	border:1px solid gray;
+    background-color:white;
+    border:1px solid gray;
     z-index: 1000;
 }
 .map_context_menu_item{
-	padding:3px 6px;
+    padding:3px 6px;
 }
 .map_context_menu_item:hover{
-	background-color:#CCCCCC;
+    background-color:#CCCCCC;
 }
 .map_context_menu_separator{
-	background-color:gray;
-	height:1px;
-	margin:0;
-	padding:0;
+    background-color:gray;
+    height:1px;
+    margin:0;
+    padding:0;
 }
 
 .disabled-context-menu-item {    
@@ -936,4 +936,9 @@
 
 .small-horizonal-spacing{
     margin-left: 5px;    
+}
+
+form.ng-submitted .ng-invalid {
+    border-color: red;
+    border-width: 2px;
 }
\ No newline at end of file

=== 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	2015-05-08 18:38:58 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/defaultForm.html	2015-05-22 10:23:04 +0000
@@ -24,31 +24,35 @@
                     {{selectedProgramStage.reportDateDescription ? selectedProgramStage.reportDateDescription : 'incident_date'| translate }}<span class="required">*</span>
                 </td>
                 <td>
-                    <input type="text"                           
+                    <input type="text"                                                   
                            placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                            d2-date
                            max-date='0'
                            ng-model="currentEvent.eventDate"
                            ng-disabled="editingEventInFull"    
                            ng-required="true" 
-                           name="eventDate"
-                           input-field-id="eventDate"
-                           style="width:99%;"/>
-                    <span ng-show="outerForm.eventDate.$invalid && outerForm.eventDate.$dirty || currentEvent.eventDate && outerForm.eventDate.$invalid || outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{getErrorMessage('eventDate')}}</span>                    
+                           ng-model-options="{ updateOn: 'blur' }"
+                           d2-date-validator
+                           name="eventDate" 
+                           input-field-id='eventDate' 
+                           style="width:99%;">
+                    <div ng-messages="outerForm.eventDate.$error" ng-if="interacted(outerForm.eventDate)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                                         
+                    </div>
                 </td>
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
                 <td>
                     {{'latitude'| translate}}<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>
-                    <input type="number"
-                           ng-model="currentEvent.coordinate.latitude"                                                                
+                    <input type="number" 
+                           ng-model="currentEvent.coordinate.latitude"   
+                           ng-model-options="{ updateOn: 'blur' }"
                            name="latitude"
-                           min="-90"
-                           max="90"
+                           d2-coordinate-validator
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>                    
+                    <div ng-messages="outerForm.latitude.$error" ng-if="interacted(outerForm.latitude)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                        
+                    </div>
                 </td>                                            
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -56,17 +60,17 @@
                     {{'longitude'| translate}}<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>
                 <td>
-                    <input type="number"  
-                           ng-model="currentEvent.coordinate.longitude"                                                                
+                    <input type="number" 
+                           ng-model="currentEvent.coordinate.longitude"   
+                           ng-model-options="{ updateOn: 'blur' }"
                            name="longitude" 
-                           min="-180"
-                           max="180"
+                           d2-coordinate-validator
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
+                    <div ng-messages="outerForm.longitude.$error" ng-if="interacted(outerForm.longitude)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">
+                    </div>
                 </td>                                                            
-            </tr>
-            
+            </tr>            
             <tr ng-repeat="eventGridColumn in eventGridColumns" ng-if="eventGridColumn.id !== 'comment' && eventGridColumn.id !== 'uid' && eventGridColumn.id !== 'event_date'">
                 <td >
                     {{eventGridColumn.name}}<span ng-if="eventGridColumn.compulsory" class="required">*</span>
@@ -78,11 +82,11 @@
                                 <input type="text"
                                        class="typeahead"
                                        placeholder="&#xf0d7;&nbsp;&nbsp;"                                                 
-                                       ng-model="currentEvent[eventGridColumn.id]"                                                                    
+                                       ng-model="currentEvent[eventGridColumn.id]"   
+                                       ng-model-options="{ updateOn: 'blur' }"
                                        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   
                                        typeahead-editable=false
-                                       d2-typeahead-validation
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo" 
                                        input-field-id={{eventGridColumn.id}} 
@@ -109,10 +113,11 @@
                         </div>
                         <div ng-if="!prStDes[eventGridColumn.id].dataElement.optionSetValue" ng-switch="eventGridColumn.type">
                             <div ng-switch-when="int">
-                                <input type="text"                                         
-                                       d2-number-validation 
+                                <input type="number"                                         
+                                       d2-number-validator
                                        number-type={{prStDes[eventGridColumn.id].dataElement.numberType}}
-                                       ng-model="currentEvent[eventGridColumn.id]"                                                                
+                                       ng-model="currentEvent[eventGridColumn.id]"                       
+                                       ng-model-options="{ updateOn: 'blur' }"
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo" 
                                        input-field-id={{eventGridColumn.id}} 
@@ -141,7 +146,9 @@
                                 <input type="text"                                                                
                                        placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                                        d2-date
-                                       max-date="prStDes[eventGridColumn.id].allowFutureDate ? '' : 0"                                         
+                                       max-date="prStDes[eventGridColumn.id].allowFutureDate ? '' : 0" 
+                                       ng-model-options="{ updateOn: 'blur' }"
+                                       d2-date-validator
                                        ng-model="currentEvent[eventGridColumn.id]"                                                               
                                        ng-required={{eventGridColumn.compulsory}}
                                        name="foo" 
@@ -156,7 +163,9 @@
                                        input-field-id={{eventGridColumn.id}} />
                             </div>
                         </div>
-                        <span ng-show="innerForm.foo.$invalid && innerForm.foo.$dirty || currentEvent[eventGridColumn.id] && innerForm.foo.$invalid || outerForm.submitted && innerForm.foo.$invalid" class="required">{{getErrorMessage(eventGridColumn.id)}}</span>                        
+                        <!--<span ng-show="innerForm.foo.$invalid && innerForm.foo.$dirty || currentEvent[eventGridColumn.id] && innerForm.foo.$invalid || outerForm.submitted && innerForm.foo.$invalid" class="required">{{getErrorMessage(eventGridColumn.id)}}</span>                        -->
+                        <div ng-messages="innerForm.foo.$error" ng-if="interacted(innerForm.foo)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                                         
+                       </div>
                     </ng-form>                    
                 </td>
             </tr>        
@@ -164,18 +173,8 @@
     </table>    
 </div>
 <div ng-class="" ng-if='selectedProgramStage.programStageSections.length'>
-    <table class="dhis2-list-table-striped">                    
-        <thead>                        
-            <tr>
-                <th>
-                    {{'data_element'| translate}}                    
-                </th>
-                <th>
-                    {{'value'| translate}}                    
-                </th>         
-            </tr>                        
-        </thead>
-        <tbody id="list">
+    <table class="dhis2-list-table-striped">        
+        <tbody>
             <tr ng-if="selectedProgramStage.preGenerateUID && currentEvent['uid']">
                 <td>
                     {{'form_id' | translate}}
@@ -196,10 +195,13 @@
                            ng-model="currentEvent.eventDate"
                            ng-disabled="editingEventInFull"    
                            ng-required="true" 
+                           ng-model-options="{ updateOn: 'blur' }"
+                           d2-date-validator
                            name="eventDate" 
                            input-field-id='eventDate' 
                            style="width:99%;">
-                    <span ng-show="outerForm.eventDate.$invalid && outerForm.eventDate.$dirty || currentEvent.eventDate && outerForm.eventDate.$invalid || outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{getErrorMessage('eventDate') | translate}}</span>
+                    <div ng-messages="outerForm.eventDate.$error" ng-if="interacted(outerForm.eventDate)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                                         
+                    </div>
                 </td>
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -208,13 +210,14 @@
                 </td>
                 <td>
                     <input type="number" 
-                           ng-model="currentEvent.coordinate.latitude"                                                                
+                           ng-model="currentEvent.coordinate.latitude"   
+                           ng-model-options="{ updateOn: 'blur' }"
                            name="latitude"
-                           min="-90"
-                           max="90"
+                           d2-coordinate-validator
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>
+                    <div ng-messages="outerForm.latitude.$error" ng-if="interacted(outerForm.latitude)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                        
+                    </div>
                 </td>                                            
             </tr>
             <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -223,13 +226,14 @@
                 </td>
                 <td>
                     <input type="number" 
-                           ng-model="currentEvent.coordinate.longitude"                                                                
+                           ng-model="currentEvent.coordinate.longitude"   
+                           ng-model-options="{ updateOn: 'blur' }"
                            name="longitude" 
-                           min="-180"
-                           max="180"
+                           d2-coordinate-validator
                            ng-required="false"
                            style="width:99%;"/>
-                    <span ng-show="outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
+                    <div ng-messages="outerForm.longitude.$error" ng-if="interacted(outerForm.longitude)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">
+                    </div>
                 </td>                                            
             </tr>        
         </tbody>
@@ -247,19 +251,19 @@
                         </th>         
                     </tr>                        
                 </thead>
-                <tbody id="list">       
+                <tbody>       
                     <tr ng-repeat="de in section.programStageDataElements">
                         <td >
-                            {{prStDes[de.dataElement.id].dataElement.formName ? prStDes[de.dataElement.id].dataElement.formName : prStDes[de.dataElement.id].dataElement.name}}<span ng-if="prStDes[de.dataElement.id].compulsory" class="required">*</span>
-                        </td>
+                            {{prStDes[de.dataElement.id].dataElement.formName ? prStDes[de.dataElement.id].dataElement.formName : prStDes[de.dataElement.id].dataElement.name}}<span ng-if="prStDes[de.dataElement.id].compulsory" class="required">*</span>                        </td>
                         <td >
                             <ng-form name="innerForm">
                                 <div ng-switch="prStDes[de.dataElement.id].dataElement.type">
                                     <div ng-switch-when="int">
                                         <input type="number"                                                
-                                               d2-number-validation 
+                                               d2-number-validator 
                                                number-type={{prStDes[de.dataElement.id].dataElement.numberType}}
-                                               ng-model="currentEvent[de.dataElement.id]"                                                                
+                                               ng-model="currentEvent[de.dataElement.id]" 
+                                               ng-model-options="{ updateOn: 'blur' }"
                                                ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                name="foo" 
                                                input-field-id={{de.dataElement.id}} 
@@ -271,11 +275,11 @@
                                                 <input type="text"
                                                        class="typeahead"
                                                        placeholder="&#xf0d7;&nbsp;&nbsp;"                                                         
-                                                       ng-model="currentEvent[de.dataElement.id]"                                                                    
+                                                       ng-model="currentEvent[de.dataElement.id]" 
+                                                       ng-model-options="{ updateOn: 'blur' }"
                                                        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   
                                                        typeahead-editable="false"
-                                                       d2-typeahead-validation
                                                        ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                        name="foo" 
                                                        input-field-id={{de.dataElement.id}} 
@@ -303,6 +307,7 @@
                                         <div ng-if="!prStDes[de.dataElement.id].dataElement.optionSet">
                                             <input type="text"                                                  
                                                 ng-model="currentEvent[de.dataElement.id]"
+                                                ng-model-options="{ updateOn: 'blur' }"
                                                 ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                 name="foo" 
                                                 input-field-id={{de.dataElement.id}} 
@@ -310,7 +315,8 @@
                                         </div>
                                     </div>
                                     <div ng-switch-when="bool">
-                                        <select ng-model="currentEvent[de.dataElement.id]"                                                                
+                                        <select ng-model="currentEvent[de.dataElement.id]"      
+                                                ng-model-options="{ updateOn: 'blur' }"
                                                 ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                 name="foo" 
                                                 input-field-id={{de.dataElement.id}} 
@@ -324,7 +330,9 @@
                                         <input type="text"                                                                
                                                placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
                                                d2-date
-                                               max-date="prStDes[de.dataElement.id].allowFutureDate ? '' : 0"                                                 
+                                               max-date="prStDes[de.dataElement.id].allowFutureDate ? '' : 0"   
+                                               ng-model-options="{ updateOn: 'blur' }"
+                                               d2-date-validator
                                                ng-model="currentEvent[de.dataElement.id]"                                                               
                                                ng-required={{prStDes[de.dataElement.id].compulsory}}
                                                name="foo" 
@@ -339,7 +347,8 @@
                                                input-field-id={{de.dataElement.id}}/>
                                     </div>
                                 </div>
-                                <span ng-show="innerForm.foo.$invalid && innerForm.foo.$dirty  || outerForm.submitted && innerForm.foo.$invalid || currentEvent[de.dataElement.id] && innerForm.foo.$invalid" class="required">{{getErrorMessage(de.dataElement.id)}}</span>                                
+                                <div ng-messages="innerForm.foo.$error" ng-if="interacted(innerForm.foo)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                                         
+                                </div>
                             </ng-form>                            
                         </td>
                     </tr>
@@ -374,7 +383,6 @@
 </div>
 <!-- comment section ends -->
 
-
 <!-- buttons for event registration / update begins -->
 <div style="clear: both;">                        
     <span ng-if="editingEventInFull">
@@ -385,8 +393,7 @@
         <button type="button" ng-disabled="disableSaveAndAddNew" ng-click="addEvent(true)" class="button hideInPrint">{{'save_and_add_new'| translate}}</button>
         <button type="button" ng-click="addEvent()" class="button hideInPrint">{{'save_and_back'| translate}}</button>
         <button type="button" ng-click="cancel()" class="button hideInPrint">{{'cancel'| translate}}</button>        
-    </span>
-    <span ng-if="isFormInvalid()" class="horizontal-spacing red">{{'form_invalid' | translate}}</span>
-        
+    </span>    
+    <br><span ng-if="isFormInvalid()" class="horizontal-spacing red">{{'form_invalid' | translate}}</span>    
 </div>
 <!-- buttons for event registration / update ends -->

=== modified 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	2015-04-20 11:29:12 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-event-capture/views/ec-custom-form.html	2015-05-22 10:23:04 +0000
@@ -13,29 +13,34 @@
         </td>
         <td>
             <input type="text"                                                   
-                   placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
-                   d2-date
-                   max-date='0'
-                   ng-model="currentEvent.eventDate"
-                   ng-disabled="editingEventInFull"    
-                   ng-required="true" 
-                   input-field-id="eventDate"
-                   name="eventDate"/>
-            <span ng-show="outerForm.eventDate.$invalid && outerForm.eventDate.$dirty || currentEvent.eventDate && outerForm.eventDate.$invalid || outerForm.submitted && outerForm.eventDate.$invalid" class="required">{{getErrorMessage('eventDate')}}</span>
+                    placeholder="{{dhis2CalendarFormat.keyDateFormat}}"
+                    d2-date
+                    max-date='0'
+                    ng-model="currentEvent.eventDate"
+                    ng-disabled="editingEventInFull"    
+                    ng-required="true" 
+                    ng-model-options="{ updateOn: 'blur' }"
+                    d2-date-validator
+                    name="eventDate" 
+                    input-field-id='eventDate' 
+                    style="width:99%;">
+            <div ng-messages="outerForm.eventDate.$error" ng-if="interacted(outerForm.eventDate)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                                         
+            </div>
         </td>
     </tr>
     <tr ng-if="selectedProgramStage.captureCoordinates">
         <td>
-            {{'latitude'| translate}}<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>
+            {{'latitude'| translate}}<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>
-            <input type="number"
-                   ng-model="currentEvent.coordinate.latitude"                                                                
+            <input type="number" 
+                   ng-model="currentEvent.coordinate.latitude"   
+                   ng-model-options="{ updateOn: 'blur' }"
                    name="latitude"
-                   min="-90"
-                   max="90"
+                   d2-coordinate-validator
                    ng-required="false"
                    style="width:99%;"/>
-            <span ng-show="outerForm.latitude.$invalid" class="required">{{'int_required'| translate}} [-90 ... 90]</span>                    
+            <div ng-messages="outerForm.latitude.$error" ng-if="interacted(outerForm.latitude)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">                        
+            </div>
         </td>                                            
     </tr>
     <tr ng-if="selectedProgramStage.captureCoordinates">
@@ -43,18 +48,19 @@
             {{'longitude'| translate}}<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>
         <td>
-            <input type="number"  
-                   ng-model="currentEvent.coordinate.longitude"                                                                
+            <input type="number" 
+                   ng-model="currentEvent.coordinate.longitude"   
+                   ng-model-options="{ updateOn: 'blur' }"
                    name="longitude" 
-                   min="-180"
-                   max="180"
+                   d2-coordinate-validator
                    ng-required="false"
                    style="width:99%;"/>
-            <span ng-show="outerForm.longitude.$invalid" class="required">{{'int_required'| translate}}[-180 ... 180]</span>
+            <div ng-messages="outerForm.longitude.$error" ng-if="interacted(outerForm.longitude)" class="required" ng-messages-include="../dhis-web-commons/angular-forms/error-messages.html">
+            </div>
         </td>                                                            
     </tr>
 </table>
-<div ng-include="'../dhis-web-commons/customform/custom-form.html'"></div>
+<div ng-include="'../dhis-web-commons/angular-forms/custom-form.html'"></div>
 
 <div class="clear">
     <hr>
@@ -93,6 +99,6 @@
         <button type="button" ng-click="addEvent()" class="button hideInPrint">{{'save_and_back'| translate}}</button>
         <button type="button" ng-click="cancel()" class="button hideInPrint">{{'cancel'| translate}}</button>
     </span>
-    <span ng-if="isFormInvalid()" class="horizontal-spacing red">{{'form_invalid' | translate}}</span>
+    <br><span ng-if="isFormInvalid()" class="horizontal-spacing red">{{'form_invalid' | translate}}</span>
 </div>
 <!-- buttons for event registration / update ends -->
\ No newline at end of file

=== removed directory 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/coordinatecapture'
=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/coordinatecapture/map.html'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/coordinatecapture/map.html	2015-05-08 19:45:51 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/coordinatecapture/map.html	1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-<div class="modal-header remove-default-padding">
-    <h2>
-        {{'point_and_click_for_coordinate'| translate}}        
-    </h2>
-</div>
-<div class="modal-body remove-default-padding">
-    <div class="align-center">
-        <span id='polygon-label'></span>
-    </div>    
-    <d2-google-map location="location" id="map-container"></d2-google-map>
-</div>
-<div class="modal-footer remove-default-padding">
-    <button class="btn btn-primary" data-ng-click="captureCoordinate()">{{'capture'| translate}}</button>
-    <button class="btn btn-default" data-ng-click="close()">{{'cancel'| translate}}</button>        
-</div>
\ No newline at end of file

=== removed directory 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/customform'
=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/customform/custom-form.html'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/customform/custom-form.html	2014-12-08 16:37:23 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/customform/custom-form.html	1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-<d2-custom-form custom-form="customForm"></d2-custom-form>
\ No newline at end of file

=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-static-files.min.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-static-files.min.js	2014-03-17 14:48:42 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-static-files.min.js	1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
-angular.module("pascalprecht.translate")
-       .factory("$translateStaticFilesLoader", ["$q", "$http", function(a, b) {
-        return function(c) {
-                if (!c || !c.prefix || !c.suffix)
-                        throw new Error(
-                                        "Couldn't load static files, no prefix or suffix specified!");
-                var d = a.defer();
-                return b(
-                                {
-                                        url : [ c.prefix, c.key, c.suffix ]
-                                                        .join(""),
-                                        method : "GET",
-                                        params : ""
-                                }).success(function(a) {
-                        d.resolve(a)
-                }).error(function() {
-                        d.reject(c.key)
-                }), d.promise
-        }
-} ]);
\ No newline at end of file

=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-url.min.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-url.min.js	2014-03-17 14:48:42 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/angular/plugins/angular-translate-loader-url.min.js	1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
-angular
-		.module("pascalprecht.translate")
-		.factory(
-				"$translateUrlLoader",
-				[
-						"$q",
-						"$http",
-						function(a, b) {
-							return function(c) {
-								if (!c || !c.url)
-									throw new Error(
-											"Couldn't use urlLoader since no url is given!");
-								var d = a.defer();
-								return b({
-									url : c.url,
-									params : {
-										lang : c.key
-									},
-									method : "GET"
-								}).success(function(a) {
-									d.resolve(a)
-								}).error(function() {
-									d.reject(c.key)
-								}), d.promise
-							}
-						} ]);
\ No newline at end of file

=== removed file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/paging/serverside-pagination.html'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/paging/serverside-pagination.html	2015-04-16 14:19:23 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/paging/serverside-pagination.html	1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
-<div class="paging-container">
-    <table style="background-color: #ebf0f6;" width='100%'>
-        <tr>
-            <td>
-                {{'total_number_of_pages'| translate}}: {{pager.pageCount}}
-            </td>
-            <td>
-                <span>{{'rows_per_page'| translate}}:</span> <input type="text" min="1" style="width:50px;" ng-model="pager.pageSize" d2-enter="resetPageSize()" ng-blur="resetPageSize()"> 
-            </td>
-            <td>
-                <span>{{'jump_to_page'| translate}}:</span> <input type="text" min="1" style="width:50px;" ng-model="pager.page" d2-enter="jumpToPage()" ng-blur="jumpToPage()"> 
-            </td>
-        </tr>
-        <tr>
-            <td colspan="3"><hr/></td>
-        </tr>
-        <tr>
-            <td colspan="3">
-                <div class="paging">
-                    <span ng-show="pager.page > 1">
-                        <a href ng-click="getPage(1)" title="{{'first'| translate}}"> 
-                            &laquo;&laquo;
-                        </a>
-                        <a href ng-click="getPage(pager.page - 1)" title="{{'previous'| translate}}"> 
-                            &laquo;
-                        </a>                    
-                    </span>
-                    <span ng-hide="pager.page > 1">
-                        <span title="{{'first'| translate}}">&laquo;&laquo;</span>
-                        <span title="{{'previous'| translate}}">&laquo;</span>
-                    </span>
-                    <a href ng-click="getPage(i+1)" title="{{'page'| translate}} {{i + 1}}" ng-repeat="i in []| forLoop:paginator.lowerLimit():pager.pageCount | limitTo : pager.toolBarDisplay" ng-class="pager.page == i + 1 && 'active'">
-                        {{i + 1}}
-                    </a>
-
-                    <span ng-show="pager.page < pager.pageCount">
-                        <a href ng-click="getPage(pager.page + 1)" title="{{'next'| translate}}" > 
-                            &raquo;
-                        </a>
-                        <a href ng-click="getPage(pager.pageCount)" title="{{'last'| translate}}"> 
-                            &raquo;&raquo;
-                        </a>
-                    </span>
-                    <span ng-hide="pager.page < pager.pageCount">
-                        <span class="next" title="{{'next'| translate}}">&raquo; </span>
-                        <span class="last" title="{{'last'| translate}}">&raquo;&raquo;</span>
-                    </span>
-                </div>
-            </td>
-        </tr>
-    </table>   
-</div>
\ No newline at end of file