← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 20319: tracker-capture: registering tracker-associate - WIP

 

------------------------------------------------------------
revno: 20319
committer: Abyot Asalefew Gizaw <abyota@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2015-09-23 16:06:13 +0200
message:
  tracker-capture: registering tracker-associate - WIP
removed:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/add-relationship.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/search.html
added:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/search.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tei-add-controller.js
modified:
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-registration-form.html
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js
  dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties
  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/styles/style.css


--
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-tracker-capture/components/registration/default-registration-form.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-registration-form.html	2015-09-23 12:05:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/default-registration-form.html	2015-09-23 14:06:13 +0000
@@ -92,7 +92,7 @@
                                ng-blur="teiValueUpdated(selectedTei, attribute.id)"
                                style="width:85%;"
                                ng-required="attribute.mandatory || attribute.unique"/>
-                        <a href ng-class="{true: 'disable-clicks', false: ''} [editingDisabled]" ng-click="getTrackerAssociate(attribute.id)" title="{{'get'| translate}} {{attribute.name}}">
+                        <a href ng-class="{true: 'disable-clicks', false: ''} [editingDisabled]" ng-click="getTrackerAssociate(attribute)" title="{{'add'| translate}} {{attribute.name}}">
                             <i class="fa fa-external-link fa-2x vertical-center"></i>
                         </a>
                     </span>

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2015-09-23 12:05:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/registration/registration-controller.js	2015-09-23 14:06:13 +0000
@@ -5,6 +5,7 @@
                 $scope,
                 $location,
                 $timeout,
+                $modal,
                 AttributesFactory,
                 DHIS2EventFactory,
                 TEService,
@@ -374,7 +375,40 @@
         return status;        
     };
     
-    $scope.getTrackerAssociate = function(attributeId){
-        console.log('the attribute is:  ', attributeId);
+    $scope.getTrackerAssociate = function(selectedAttribute){
+        
+        
+        var modalInstance = $modal.open({
+            templateUrl: 'components/teiadd/tei-add.html',
+            controller: 'TEIAddController',
+            windowClass: 'modal-full-window',
+            resolve: {
+                relationshipTypes: function () {
+                    return $scope.relationshipTypes;
+                },
+                addingRelationship: function(){
+                    return false;
+                },
+                selections: function () {
+                    return CurrentSelection.get();
+                },
+                selectedTei: function(){
+                    return $scope.selectedTei;
+                },
+                selectedAttribute: function(){
+                    return selectedAttribute;
+                },
+                selectedProgram: function(){
+                    return $scope.selectedProgram;
+                },
+                relatedProgramRelationship: function(){
+                    return $scope.relatedProgramRelationship;
+                }
+            }
+        });
+
+        modalInstance.result.then(function (res) {
+            console.log('the result:  ', res);
+        });
     };    
 });

=== removed file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/add-relationship.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/add-relationship.html	2015-09-14 15:16:33 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/add-relationship.html	1970-01-01 00:00:00 +0000
@@ -1,120 +0,0 @@
-<div class="modal-header page">
-    <h2>{{'add_relationship'| translate}}</h2>
-</div>
-<div class="modal-body">
-    <div class='row'>
-        <div class='col-md-12'>
-            <select ng-model="relationship.selected"
-                    class="form-control"
-                    ng-options="rel as rel.name for rel in relationshipTypes | orderBy: 'name'"
-                    ng-disabled="relatedProgramRelationship">
-                <option value="">{{'please_select_a_relationship'| translate}}</option>
-            </select>
-        </div>
-    </div>
-
-    <div class="row" ng-show="relationship.selected">
-        <hr>
-        <div class="col-md-4">
-            <select name="foo" 
-                    ng-model="selectedRelationship.aIsToB" 
-                    class="form-control" 
-                    ng-change="setRelationshipSides('A')"
-                    ng-disabled="selectedProgramForRelative && selectedProgram.relatedProgram && relatedProgramRelationship">
-                <option>{{relationship.selected.aIsToB}}</option>
-                <option>{{relationship.selected.bIsToA}}</option>
-            </select>
-            <div class='relationship-container'>
-                <table class="table table-striped table-compact table-borderless">
-                    <tr ng-repeat="attribute in selectedTeiForDisplay.attributes">
-                        <td>
-                            {{attribute.displayName}}
-                        </td>
-                        <td>
-                            {{attribute.value}}                                                                                                  
-                        </td>
-                    </tr>           
-                </table>
-            </div>
-        </div>
-        <div class="col-md-8 pull-right">
-            <select name="foo" 
-                    ng-model="selectedRelationship.bIsToA" 
-                    class="form-control" 
-                    ng-change="setRelationshipSides('B')"
-                    ng-disabled="selectedProgramForRelative && selectedProgram.relatedProgram && relatedProgramRelationship">    
-                <option>{{relationship.selected.aIsToB}}</option>
-                <option>{{relationship.selected.bIsToA}}</option>
-            </select>
-            <div class='relationship-container' ng-show="teiForRelationship">
-                <button class="btn btn-warning" type="button" ng-click="back()">{{'back' | translate}}</button>
-                <table class="table table-striped table-compact table-borderless">
-                    <tr ng-repeat="gridColumn in gridColumns">
-                        <td>
-                            {{gridColumn.name}}
-                        </td>
-                        <td >                                                
-                            {{teiForRelationship[gridColumn.id]}}                                                
-                        </td> 
-                    </tr>
-                </table>                
-            </div>
-            <div class='relationship-container' ng-show="!teiForRelationship">
-
-                <div class="row">
-                    
-                    <div class="col-sm-4 vertical-spacing">
-                        <select ng-model="selectedProgramForRelative"
-                                class="form-control"
-                                ng-disabled="programs.length < 1 || (selectedProgramForRelative && selectedProgram.relatedProgram && relatedProgramRelationship)"
-                                ng-options="program as program.name for program in programs | orderBy: 'name'" 
-                                ng-change="setAttributesForSearch(selectedProgramForRelative)">
-                            <option value="">{{'please_select_a_program'| translate}}</option>
-                        </select>                
-                    </div>
-
-                    <div class="input-group col-sm-8 vertical-spacing">
-                        <input type="text" placeholder="{{'type_your_search_criteria_here'| translate}}" ng-model="searchText.value" d2-enter="search(searchMode.freeText)" class="form-control expanded" ng-class="{true: 'invalid - input'} [!searchText && emptySearchText]" ng-focus="showHideSearch(true)">
-                        <div class="input-group-btn">
-                            <button class="btn btn-default without-border-radius trim" type="button" title="{{'advanced_search'| translate}}" ng-click="showHideSearch(false)"><i class="fa fa-caret-down"></i></button>
-                            <button class="btn btn-primary without-border-radius trim" type="button" title="{{'search'| translate}}" ng-click="search(searchMode.freeText)"><i class="fa fa-search"></i></button>                            
-                            <button class="btn btn-default without-border-radius trim" type="button" title="{{'list_all'| translate}}" ng-disabled="showRegistrationDiv" ng-click="search(searchMode.listAll)"><i class="fa fa-list"></i></button>
-                            <button class="btn btn-success trim" type="button" title="{{'register'| translate}}" ng-click="showRegistration()"><i class="fa fa-plus-square"></i></button>                            
-                        </div>                
-                    </div>
-                    
-                </div>
-
-                <div ng-if="showAdvancedSearchDiv">
-                    <div ng-include="'components/relationship/search.html'"></div>     
-                    <span>&nbsp;</span>
-                </div>
-
-                <!-- entity grid begins -->
-                <div class="row" ng-if="showTrackedEntityDiv">
-                    <img class="col-md-12" src="../images/ajax-loader-bar.gif" ng-if="!teiFetched"/>
-                    <div class="col-md-12" ng-include="'views/tei.html'"></div>                        
-                </div>
-                <!-- entity grid ends -->
-
-                <!--- Error display for search begins -->
-                <div class="row" ng-if="emptySearchAttribute || !searchText.value && emptySearchText">
-                    <div class="col-md-12 vertical-spacing">
-                        <div class="alert alert-danger">{{'search_input_required'| translate}}</div>         
-                    </div>
-                </div>
-                <!--- Error display for search ends -->
-
-                <div ng-show="showRegistrationDiv">
-                    <!--<div ng-include="'components/relationship/registration.html'"></div>-->
-                    <div ng-include="'components/registration/registration.html'"></div>
-                    <span>&nbsp;</span>
-                </div>
-            </div>
-        </div>        
-    </div>
-</div>
-<div class="modal-footer">        
-    <button class="btn btn-primary trim" data-ng-click="addRelationship()" ng-disabled='!teiForRelationship'>{{'save_relationship'| translate}}</button>
-    <button class="btn btn-default" data-ng-click="close()">{{'close'| translate}}</button>    
-</div> 
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2015-09-14 16:13:56 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/relationship-controller.js	2015-09-23 14:06:13 +0000
@@ -52,13 +52,19 @@
        
         if($rootScope.showAddRelationshipDiv){
             var modalInstance = $modal.open({
-                templateUrl: 'components/relationship/add-relationship.html',
-                controller: 'AddRelationshipController',
+                templateUrl: 'components/teiadd/tei-add.html',
+                controller: 'TEIAddController',
                 windowClass: 'modal-full-window',
                 resolve: {
                     relationshipTypes: function () {
                         return $scope.relationshipTypes;
                     },
+                    selectedAttribute: function(){
+                        return null;
+                    },
+                    addingRelationship: function(){
+                        return true;
+                    },
                     selections: function () {
                         return $scope.selections;
                     },
@@ -75,8 +81,7 @@
             });
 
             modalInstance.result.then(function (relationships) {
-                $scope.selectedTei.relationships = relationships;
-                
+                $scope.selectedTei.relationships = relationships;                
                 setRelationships();
             });
         }
@@ -169,397 +174,4 @@
         
         return attributes;
     };
-})
-
-//Controller for adding new relationship
-.controller('AddRelationshipController', 
-    function($scope, 
-            $rootScope,
-            $translate,
-            $timeout,
-            DateUtils,
-            CurrentSelection,
-            OperatorFactory,
-            AttributesFactory,
-            EntityQueryFactory,
-            TEIService,
-            TEIGridService,
-            DialogService,
-            Paginator,
-            SessionStorageService,
-            $modalInstance, 
-            relationshipTypes,
-            selectedProgram,
-            relatedProgramRelationship,
-            selections,
-            selectedTei){
-    
-    $scope.relationshipTypes = relationshipTypes;
-    $scope.selectedProgram = selectedProgram;
-    $scope.relatedProgramRelationship = relatedProgramRelationship;
-    $scope.selectedTei = selectedTei;
-    $scope.programs = selections.prs;
-    $scope.attributesById = CurrentSelection.getAttributesById();
-    
-    $scope.selectedRelationship = {};
-    $scope.relationship = {};
-    
-    var invalidTeis = [];
-    invalidTeis.push($scope.selectedTei.trackedEntityInstance);
-    angular.forEach($scope.selectedTei.relationships, function(rel){
-        invalidTeis.push(rel.trackedEntityInstanceB);
-    });
-
-    //Selections
-    $scope.selectedOrgUnit = SessionStorageService.get('SELECTED_OU');
-    $scope.optionSets = selections.optionSets;
-    $scope.selectedTeiForDisplay = angular.copy($scope.selectedTei);
-    $scope.ouModes = [{name: 'SELECTED'}, {name: 'CHILDREN'}, {name: 'DESCENDANTS'}, {name: 'ACCESSIBLE'}];         
-    $scope.selectedOuMode = $scope.ouModes[0];
-    
-    //Paging
-    $scope.pager = {pageSize: 50, page: 1, toolBarDisplay: 5}; 
-    
-    //Searching
-    $scope.showAdvancedSearchDiv = false;
-    $scope.searchText = {value: null};
-    $scope.emptySearchText = false;
-    $scope.searchFilterExists = false;   
-    $scope.defaultOperators = OperatorFactory.defaultOperators;
-    $scope.boolOperators = OperatorFactory.boolOperators;
-    
-    $scope.trackedEntityList = null; 
-    $scope.enrollment = {programStartDate: '', programEndDate: '', operator: $scope.defaultOperators[0]};
-   
-    $scope.searchMode = {listAll: 'LIST_ALL', freeText: 'FREE_TEXT', attributeBased: 'ATTRIBUTE_BASED'};
-    $scope.selectedSearchMode = $scope.searchMode.listAll;
-    
-    if(angular.isObject($scope.programs) && $scope.programs.length === 1){
-        $scope.selectedProgramForRelative = $scope.programs[0];        
-    } 
-    
-    if($scope.selectedProgram){
-        if($scope.selectedProgram.relatedProgram && $scope.relatedProgramRelationship){
-            angular.forEach($scope.programs, function(pr){
-                if(pr.id === $scope.selectedProgram.relatedProgram.id){
-                    $scope.selectedProgramForRelative = pr;
-                }
-            });
-        }
-        
-        if($scope.selectedProgram.relationshipType){
-            angular.forEach($scope.relationshipTypes, function(rel){
-                if(rel.id === $scope.selectedProgram.relationshipType.id){
-                    $scope.relationship.selected = rel;
-                }
-            });
-        }
-    }
-    
-    //watch for selection of relationship
-    $scope.$watch('relationship.selected', function() {        
-        if( angular.isObject($scope.relationship.selected)){
-            $scope.selectedRelationship = {aIsToB: $scope.relationship.selected.aIsToB, bIsToA: $scope.relationship.selected.bIsToA};  
-        }
-    });
-    
-    function resetFields(){
-        
-        $scope.teiForRelationship = null;
-        $scope.teiFetched = false;    
-        $scope.emptySearchText = false;
-        $scope.emptySearchAttribute = false;
-        $scope.showAdvancedSearchDiv = false;
-        $scope.showRegistrationDiv = false;  
-        $scope.showTrackedEntityDiv = false;
-        $scope.trackedEntityList = null; 
-        $scope.teiCount = null;
-
-        $scope.queryUrl = null;
-        $scope.programUrl = null;
-        $scope.attributeUrl = {url: null, hasValue: false};
-        $scope.sortColumn = {};
-    }
-    
-    //listen for selections
-    $scope.$on('relationship', function(event, args){
-        if(args.result === 'SUCCESS'){
-            var relationshipInfo = CurrentSelection.getRelationshipInfo();
-            $scope.teiForRelationship = relationshipInfo.tei;
-        }
-        
-        if(args.result === 'CANCEL'){
-            $scope.showRegistration();
-        }        
-    });
-    
-    //sortGrid
-    $scope.sortGrid = function(gridHeader){
-        if ($scope.sortColumn && $scope.sortColumn.id === gridHeader.id){
-            $scope.reverse = !$scope.reverse;
-            return;
-        }        
-        $scope.sortColumn = gridHeader;
-        if($scope.sortColumn.valueType === 'date'){
-            $scope.reverse = true;
-        }
-        else{
-            $scope.reverse = false;    
-        }
-    };
-    
-    $scope.d2Sort = function(tei){        
-        if($scope.sortColumn && $scope.sortColumn.valueType === 'date'){            
-            var d = tei[$scope.sortColumn.id];         
-            return DateUtils.getDate(d);
-        }
-        return tei[$scope.sortColumn.id];
-    };
-    
-    $scope.search = function(mode){ 
-        
-        resetFields();
-        
-        $scope.selectedSearchMode = mode;        
-   
-        if($scope.selectedProgramForRelative){
-            $scope.programUrl = 'program=' + $scope.selectedProgramForRelative.id;
-        }        
-        
-        //check search mode
-        if( $scope.selectedSearchMode === $scope.searchMode.freeText ){ 
-            
-            if(!$scope.searchText.value){                
-                $scope.emptySearchText = true;
-                $scope.teiFetched = false;   
-                $scope.teiCount = null;
-                return;
-            }       
-
-            $scope.queryUrl = 'query=LIKE:' + $scope.searchText.value;                     
-        }
-        
-        if( $scope.selectedSearchMode === $scope.searchMode.attributeBased ){            
-            $scope.searchText.value = null;
-            $scope.attributeUrl = EntityQueryFactory.getAttributesQuery($scope.attributes, $scope.enrollment);
-            
-            if(!$scope.attributeUrl.hasValue && !$scope.selectedProgramForRelative){
-                $scope.emptySearchAttribute = true;
-                $scope.teiFetched = false;   
-                $scope.teiCount = null;
-                return;
-            }
-        }
-        
-        $scope.fetchTei();
-    };
-    
-    $scope.fetchTei = function(){
-
-        //get events for the specified parameters
-        TEIService.search($scope.selectedOrgUnit.id, 
-                                            $scope.selectedOuMode.name,
-                                            $scope.queryUrl,
-                                            $scope.programUrl,
-                                            $scope.attributeUrl.url,
-                                            $scope.pager,
-                                            true).then(function(data){
-            //$scope.trackedEntityList = data;            
-            if(data.rows){
-                $scope.teiCount = data.rows.length;
-            }                    
-            
-            if( data.metaData.pager ){
-                $scope.pager = data.metaData.pager;
-                $scope.pager.toolBarDisplay = 5;
-
-                Paginator.setPage($scope.pager.page);
-                Paginator.setPageCount($scope.pager.pageCount);
-                Paginator.setPageSize($scope.pager.pageSize);
-                Paginator.setItemCount($scope.pager.total);                    
-            }
-            
-            //process tei grid
-            $scope.trackedEntityList = TEIGridService.format(data,false, $scope.optionSets, invalidTeis);
-            $scope.showTrackedEntityDiv = true;
-            $scope.teiFetched = true;
-            
-            if(!$scope.sortColumn.id){                                      
-                $scope.sortGrid({id: 'created', name: $translate('registration_date'), valueType: 'date', displayInListNoProgram: false, showFilter: false, show: false});
-            }
-            
-        });
-    };
-    
-    //set attributes as per selected program
-    $scope.setAttributesForSearch = function(program){
-        
-        $scope.selectedProgramForRelative = program;
-        AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
-            $scope.attributes = atts;
-            $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
-            $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
-        });
-        
-        $scope.search( $scope.selectedSearchMode );        
-    }; 
-    
-    $scope.setAttributesForSearch( $scope.selectedProgramForRelative );
-    
-    $scope.jumpToPage = function(){
-        if($scope.pager && $scope.pager.page && $scope.pager.pageCount && $scope.pager.page > $scope.pager.pageCount){
-            $scope.pager.page = $scope.pager.pageCount;
-        }
-        
-        $scope.search($scope.selectedSearchMode);
-    };
-    
-    $scope.resetPageSize = function(){
-        $scope.pager.page = 1;        
-        $scope.search($scope.selectedSearchMode);
-    };
-    
-    $scope.getPage = function(page){
-        $scope.pager.page = page;
-        $scope.search($scope.selectedSearchMode);
-    };
-    
-    $scope.generateAttributeFilters = function(attributes){
-
-        angular.forEach(attributes, function(attribute){
-            if(attribute.valueType === 'number' || attribute.valueType === 'date'){
-                attribute.operator = $scope.defaultOperators[0];
-            }
-        });
-                    
-        return attributes;
-    };
-
-    //generate grid columns from teilist attributes
-    $scope.generateGridColumns = function(attributes){
-
-        var columns = attributes ? angular.copy(attributes) : [];
-       
-        //also add extra columns which are not part of attributes (orgunit for example)
-        columns.push({id: 'orgUnitName', name: 'Organisation unit', type: 'TEXT', displayInListNoProgram: false});
-        columns.push({id: 'created', name: 'Registration date', type: 'TEXT', displayInListNoProgram: false});
-        
-        //generate grid column for the selected program/attributes
-        angular.forEach(columns, function(column){
-            if(column.id === 'orgUnitName' && $scope.selectedOuMode.name !== 'SELECTED'){
-                column.show = true;
-            }
-            
-            if(column.displayInListNoProgram){
-                column.show = true;
-            }           
-           
-            if(column.type === 'date'){
-                $scope.filterText[column.id]= {start: '', end: ''};
-            }
-        });        
-        return columns;        
-    };   
-    
-    $scope.showHideSearch = function(simpleSearch){
-        if(simpleSearch){
-            $scope.showAdvancedSearchDiv = false;
-        }
-        else{
-            $scope.showAdvancedSearchDiv = !$scope.showAdvancedSearchDiv;
-        }
-        
-        if($scope.showAdvancedSearchDiv){
-            $scope.showTrackedEntityDiv = false;
-        }
-        else{
-            $scope.showTrackedEntityDiv = true;
-        }
-    };
-    
-    $scope.showRegistration = function(){
-        $scope.showRegistrationDiv = !$scope.showRegistrationDiv;
-        
-        if($scope.showRegistrationDiv){
-            $scope.showTrackedEntityDiv = false;
-            $timeout(function() {
-                var mainTei = angular.copy($scope.selectedTei); 
-                angular.forEach(mainTei.attributes, function(att){
-                    mainTei[att.attribute] = att.value;
-                });
-                $rootScope.$broadcast('registrationWidget', {registrationMode: 'RELATIONSHIP', mainTei: mainTei, relativeProgram: $scope.selectedProgramForRelative});
-            }, 200);
-        }
-        else{
-            $scope.showTrackedEntityDiv = true;            
-        }        
-    };
-    
-    $scope.close = function () {
-        $modalInstance.close($scope.selectedTei.relationships ? $scope.selectedTei.relationships : []);
-        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
-    };
-    
-    $scope.setRelationshipSides = function(side){
-        if(side === 'A'){            
-            $scope.selectedRelationship.bIsToA = $scope.selectedRelationship.aIsToB === $scope.relationship.selected.aIsToB ? $scope.relationship.selected.bIsToA : $scope.relationship.selected.aIsToB;
-        }
-        if(side === 'B'){
-            $scope.selectedRelationship.aIsToB = $scope.selectedRelationship.bIsToA === $scope.relationship.selected.bIsToA ? $scope.relationship.selected.aIsToB : $scope.relationship.selected.bIsToA;
-        }
-    };
-    
-    $scope.assignRelationship = function(relativeTei){
-        $scope.teiForRelationship = relativeTei;
-        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
-    };
-    
-    
-    $scope.back = function(){
-        $scope.teiForRelationship = null;
-        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
-    };
-    
-    $scope.addRelationship = function(){
-        if($scope.selectedTei && $scope.teiForRelationship && $scope.relationship.selected){            
-            var tei = angular.copy($scope.selectedTei);
-            var relationship = {};
-            relationship.relationship = $scope.relationship.selected.id;
-            relationship.displayName = $scope.relationship.selected.name;
-            relationship.relative = {};
-            
-            
-            relationship.trackedEntityInstanceA = $scope.selectedRelationship.aIsToB === $scope.relationship.selected.aIsToB ? $scope.selectedTei.trackedEntityInstance : $scope.teiForRelationship.id;
-            relationship.trackedEntityInstanceB = $scope.selectedRelationship.bIsToA === $scope.relationship.selected.bIsToA ? $scope.teiForRelationship.id : $scope.selectedTei.trackedEntityInstance;
-            
-            tei.relationships = [];
-            angular.forEach($scope.selectedTei.relationships, function(rel){
-                tei.relationships.push({relationship: rel.relationship, displayName: rel.displayName, trackedEntityInstanceA: rel.trackedEntityInstanceA, trackedEntityInstanceB: rel.trackedEntityInstanceB});
-            });
-            tei.relationships.push(relationship);
-            
-            TEIService.update(tei, $scope.optionSets, $scope.attributesById).then(function(response){
-                if(response.response && response.response.status !== 'SUCCESS'){//update has failed
-                    var dialogOptions = {
-                            headerText: 'relationship_error',
-                            bodyText: response.message
-                        };
-                    DialogService.showDialog({}, dialogOptions);
-                    return;
-                }
-                
-                relationship.relative.processed = true;
-                relationship.relative.attributes = $scope.teiForRelationship;
-                
-                if($scope.selectedTei.relationships){
-                    $scope.selectedTei.relationships.push(relationship);
-                }
-                else{
-                    $scope.selectedTei.relationships = [relationship];
-                }
-                
-                $modalInstance.close($scope.selectedTei.relationships);                
-            });
-        }        
-    };
 });
\ No newline at end of file

=== removed file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/search.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/search.html	2015-09-15 13:51:19 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/relationship/search.html	1970-01-01 00:00:00 +0000
@@ -1,115 +0,0 @@
-<div class="advanced-search-container-main">
-    <div class="advanced-search-container">    
-        <table data-stop-propagation="true" class="table-borderless table-striped">
-            <tr>
-                <td>{{orgUnitLabel}}</td>
-                <td>                    
-                    <label><input type="radio" ng-model="selectedOuMode.name" name="selected" value="SELECTED"> {{'SELECTED'| translate}}</label><br/>
-                    <label><input type="radio" ng-model="selectedOuMode.name" name="children" value="CHILDREN"> {{'CHILDREN'| translate}}</label><br/>
-                    <label><input type="radio" ng-model="selectedOuMode.name" name="descendants" value="DESCENDANTS"> {{'DESCENDANTS'| translate}}</label><br/>
-                    <label><input type="radio" ng-model="selectedOuMode.name" name="accessible" value="ACCESSIBLE"> {{'ACCESSIBLE'| translate}}</label>
-                </td>
-            </tr>            
-            <tr ng-if="selectedProgramForRelative">
-                <td>{{'enrollment_date'| translate}}</td>
-                <td>
-                    <div class="dataelement-filter">
-                        <div class="filter-operator">
-                            <select ng-model="enrollment.operator" class="form-control-select2" ng-options="operator | translate for operator in defaultOperators">
-                            </select>
-                        </div>
-                        <div class="filter-value" ng-show="enrollment.operator === defaultOperators[0]">
-                            <input type="text" placeholder="{{'exact_date'| translate}}" class="form-control-select2" d2-date ng-model="enrollment.programExactDate"/>
-                        </div>
-                        <div class="filter-value" ng-show="enrollment.operator === defaultOperators[1]">
-                            <div class="container-1-2">
-                                <input type="text" placeholder="{{'start_date'| translate}}" class="form-control-select2" d2-date ng-model="enrollment.programStartDate"/>
-                            </div>
-                            <div class="container-1-2">
-                                <input type="text" placeholder="{{'end_date'| translate}}" class="form-control-select2" d2-date ng-model="enrollment.programEndDate"/>                
-                            </div>
-                        </div>                    
-                    </div>                
-                </td>
-            </tr>
-            <tr ng-repeat="attribute in attributes">
-                <td>
-                    {{attribute.name}}
-                </td>
-                <td>
-                    <div ng-if="attribute.optionSetValue">
-                        <select multiple ui-select2  ng-model="attribute.value" data-placeholder="{{'please_select'| translate}}" style="width:100%;">
-                            <option ng-repeat="option in attribute.optionSet.options" value="{{option.code}}">{{option.name}}</option>
-                        </select>
-                    </div>
-                    <div ng-if="!attribute.optionSetValue" ng-switch="attribute.valueType">
-                        <div ng-switch-when="NUMBER">
-                            <div class="dataelement-filter">                                                
-                                <div class="filter-operator">
-                                    <select ng-model="attribute.operator" class="form-control-select2" ng-options="operator | translate for operator in defaultOperators">
-                                    </select>
-                                </div>
-                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[0]">
-                                    <input type="number" placeholder="{{'exact_value'| translate}}" class="form-control-select2" ng-model="attribute.exactValue"/>
-                                </div>
-                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[1]">
-                                    <div class="container-1-2">
-                                        <input type="number" placeholder="{{'from'| translate}}" class="form-control-select2" ng-model="attribute.startValue"/>
-                                    </div>
-                                    <div class="container-1-2">
-                                        <input type="number" placeholder="{{'to'| translate}}" class="form-control-select2" ng-model="attribute.endValue"/>                
-                                    </div>
-                                </div>                            
-                            </div>                        
-                        </div>
-                        <div ng-switch-when="DATE">
-                            <div class="dataelement-filter">
-                                <div class="filter-operator">
-                                    <select ng-model="attribute.operator" class="form-control-select2" ng-options="operator | translate for operator in defaultOperators">
-                                    </select>
-                                </div>
-                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[0]">
-                                    <input type="text" placeholder="{{'exact_date'| translate}}" class="form-control-select2" d2-date ng-model="attribute.exactValue"/>
-                                </div>
-                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[1]">
-                                    <div class="container-1-2">
-                                        <input type="text" placeholder="{{'start_date'| translate}}" class="form-control-select2" d2-date ng-model="attribute.startValue"/>
-                                    </div>
-                                    <div class="container-1-2">
-                                        <input type="text" placeholder="{{'end_date'| translate}}" class="form-control-select2" d2-date ng-model="attribute.endValue"/>                
-                                    </div>
-                                </div>                            
-                            </div> 
-                        </div>                        
-                        <div ng-switch-when="BOOLEAN">
-                            <select multiple ui-select2  ng-model="attribute.value" data-placeholder="{{'please_select'| translate}}" style="width:100%;">
-                                <option ng-repeat="option in boolOperators" value="{{option}}">{{option| translate}}</option>
-                            </select>
-                        </div> 
-                        <div ng-switch-default>
-                            <input type="text" class="form-control-select2" ng-model="attribute.value" /> 
-                        </div>
-                    </div>
-                </td>
-            </tr>         
-        </table>
-    </div>
-
-    <div class="horizonal-spacing">
-        <button type="button"
-                class="btn btn-primary"
-                ng-click="search(searchMode.attributeBased)">
-            {{'search'| translate}}
-        </button>
-        <button type="button" 
-                class="btn btn-success small-horizonal-spacing" 
-                ng-click="search(searchMode.listAll)">
-            {{'list_all'| translate}}
-        </button>
-        <button type="button" 
-                class="btn btn-default small-horizonal-spacing" 
-                ng-click="showHideSearch()">
-            {{'cancel'| translate}}
-        </button>
-    </div>
-</div>
\ No newline at end of file

=== added directory 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd'
=== added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/search.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/search.html	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/search.html	2015-09-23 14:06:13 +0000
@@ -0,0 +1,115 @@
+<div class="advanced-search-container-main">
+    <div class="advanced-search-container">    
+        <table data-stop-propagation="true" class="table-borderless table-striped">
+            <tr>
+                <td>{{orgUnitLabel}}</td>
+                <td>                    
+                    <label><input type="radio" ng-model="selectedOuMode.name" name="selected" value="SELECTED"> {{'SELECTED'| translate}}</label><br/>
+                    <label><input type="radio" ng-model="selectedOuMode.name" name="children" value="CHILDREN"> {{'CHILDREN'| translate}}</label><br/>
+                    <label><input type="radio" ng-model="selectedOuMode.name" name="descendants" value="DESCENDANTS"> {{'DESCENDANTS'| translate}}</label><br/>
+                    <label><input type="radio" ng-model="selectedOuMode.name" name="accessible" value="ACCESSIBLE"> {{'ACCESSIBLE'| translate}}</label>
+                </td>
+            </tr>            
+            <tr ng-if="selectedProgramForRelative">
+                <td>{{'enrollment_date'| translate}}</td>
+                <td>
+                    <div class="dataelement-filter">
+                        <div class="filter-operator">
+                            <select ng-model="enrollment.operator" class="form-control-select2" ng-options="operator | translate for operator in defaultOperators">
+                            </select>
+                        </div>
+                        <div class="filter-value" ng-show="enrollment.operator === defaultOperators[0]">
+                            <input type="text" placeholder="{{'exact_date'| translate}}" class="form-control-select2" d2-date ng-model="enrollment.programExactDate"/>
+                        </div>
+                        <div class="filter-value" ng-show="enrollment.operator === defaultOperators[1]">
+                            <div class="container-1-2">
+                                <input type="text" placeholder="{{'start_date'| translate}}" class="form-control-select2" d2-date ng-model="enrollment.programStartDate"/>
+                            </div>
+                            <div class="container-1-2">
+                                <input type="text" placeholder="{{'end_date'| translate}}" class="form-control-select2" d2-date ng-model="enrollment.programEndDate"/>                
+                            </div>
+                        </div>                    
+                    </div>                
+                </td>
+            </tr>
+            <tr ng-repeat="attribute in attributes">
+                <td>
+                    {{attribute.name}}
+                </td>
+                <td>
+                    <div ng-if="attribute.optionSetValue">
+                        <select multiple ui-select2  ng-model="attribute.value" data-placeholder="{{'please_select'| translate}}" style="width:100%;">
+                            <option ng-repeat="option in attribute.optionSet.options" value="{{option.code}}">{{option.name}}</option>
+                        </select>
+                    </div>
+                    <div ng-if="!attribute.optionSetValue" ng-switch="attribute.valueType">
+                        <div ng-switch-when="NUMBER">
+                            <div class="dataelement-filter">                                                
+                                <div class="filter-operator">
+                                    <select ng-model="attribute.operator" class="form-control-select2" ng-options="operator | translate for operator in defaultOperators">
+                                    </select>
+                                </div>
+                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[0]">
+                                    <input type="number" placeholder="{{'exact_value'| translate}}" class="form-control-select2" ng-model="attribute.exactValue"/>
+                                </div>
+                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[1]">
+                                    <div class="container-1-2">
+                                        <input type="number" placeholder="{{'from'| translate}}" class="form-control-select2" ng-model="attribute.startValue"/>
+                                    </div>
+                                    <div class="container-1-2">
+                                        <input type="number" placeholder="{{'to'| translate}}" class="form-control-select2" ng-model="attribute.endValue"/>                
+                                    </div>
+                                </div>                            
+                            </div>                        
+                        </div>
+                        <div ng-switch-when="DATE">
+                            <div class="dataelement-filter">
+                                <div class="filter-operator">
+                                    <select ng-model="attribute.operator" class="form-control-select2" ng-options="operator | translate for operator in defaultOperators">
+                                    </select>
+                                </div>
+                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[0]">
+                                    <input type="text" placeholder="{{'exact_date'| translate}}" class="form-control-select2" d2-date ng-model="attribute.exactValue"/>
+                                </div>
+                                <div class="filter-value" ng-show="attribute.operator === defaultOperators[1]">
+                                    <div class="container-1-2">
+                                        <input type="text" placeholder="{{'start_date'| translate}}" class="form-control-select2" d2-date ng-model="attribute.startValue"/>
+                                    </div>
+                                    <div class="container-1-2">
+                                        <input type="text" placeholder="{{'end_date'| translate}}" class="form-control-select2" d2-date ng-model="attribute.endValue"/>                
+                                    </div>
+                                </div>                            
+                            </div> 
+                        </div>                        
+                        <div ng-switch-when="BOOLEAN">
+                            <select multiple ui-select2  ng-model="attribute.value" data-placeholder="{{'please_select'| translate}}" style="width:100%;">
+                                <option ng-repeat="option in boolOperators" value="{{option}}">{{option| translate}}</option>
+                            </select>
+                        </div> 
+                        <div ng-switch-default>
+                            <input type="text" class="form-control-select2" ng-model="attribute.value" /> 
+                        </div>
+                    </div>
+                </td>
+            </tr>         
+        </table>
+    </div>
+
+    <div class="horizonal-spacing">
+        <button type="button"
+                class="btn btn-primary"
+                ng-click="search(searchMode.attributeBased)">
+            {{'search'| translate}}
+        </button>
+        <button type="button" 
+                class="btn btn-success small-horizonal-spacing" 
+                ng-click="search(searchMode.listAll)">
+            {{'list_all'| translate}}
+        </button>
+        <button type="button" 
+                class="btn btn-default small-horizonal-spacing" 
+                ng-click="showHideSearch()">
+            {{'cancel'| translate}}
+        </button>
+    </div>
+</div>
\ No newline at end of file

=== added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add-controller.js	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add-controller.js	2015-09-23 14:06:13 +0000
@@ -0,0 +1,444 @@
+/* global trackerCapture, angular */
+
+trackerCapture.controller('TEIAddController', 
+    function($scope, 
+            $rootScope,
+            $translate,
+            $timeout,
+            DateUtils,
+            CurrentSelection,
+            OperatorFactory,
+            AttributesFactory,
+            EntityQueryFactory,
+            OrgUnitFactory,
+            TEIService,
+            TEIGridService,
+            DialogService,
+            Paginator,
+            SessionStorageService,
+            $modalInstance, 
+            relationshipTypes,
+            selectedProgram,
+            relatedProgramRelationship,
+            selections,
+            selectedAttribute,
+            addingRelationship,
+            selectedTei){
+    
+    $scope.relationshipTypes = relationshipTypes;
+    $scope.addingRelationship = addingRelationship;
+    $scope.selectedAttribute = selectedAttribute;
+    $scope.selectedProgram = selectedProgram;
+    $scope.relatedProgramRelationship = relatedProgramRelationship;
+    $scope.selectedTei = selectedTei;
+    $scope.programs = selections.prs;
+    $scope.attributesById = CurrentSelection.getAttributesById();
+    
+    if($scope.addingRelationship){
+        $scope.teiAddLabel = $translate.instant('add_relationship');
+    }
+    else{        
+        $scope.teiAddLabel = $scope.selectedAttribute && $scope.selectedAttribute.name ? $scope.selectedAttribute.name : $translate.instant('tracker_associate');
+    }
+    
+    $scope.searchOuTree = false;
+    $scope.orgUnitLabel = $translate.instant('org_unit');
+    
+    $scope.selectedRelationship = {};
+    $scope.relationship = {};
+    
+    var invalidTeis = [];
+    invalidTeis.push($scope.selectedTei.trackedEntityInstance);
+    if($scope.selectedTei.relationships){
+        angular.forEach($scope.selectedTei.relationships, function(rel){
+            invalidTeis.push(rel.trackedEntityInstanceB);
+        });
+    }    
+
+    //Selections
+    $scope.selectedOrgUnit = SessionStorageService.get('SELECTED_OU');
+    $scope.optionSets = selections.optionSets;
+    $scope.selectedTeiForDisplay = angular.copy($scope.selectedTei);
+    $scope.ouModes = [{name: 'SELECTED'}, {name: 'CHILDREN'}, {name: 'DESCENDANTS'}, {name: 'ACCESSIBLE'}];         
+    $scope.selectedOuMode = $scope.ouModes[0];
+    
+    //Paging
+    $scope.pager = {pageSize: 50, page: 1, toolBarDisplay: 5}; 
+    
+    //Searching
+    $scope.showAdvancedSearchDiv = false;
+    $scope.searchText = {value: null};
+    $scope.emptySearchText = false;
+    $scope.searchFilterExists = false;   
+    $scope.defaultOperators = OperatorFactory.defaultOperators;
+    $scope.boolOperators = OperatorFactory.boolOperators;
+    
+    $scope.trackedEntityList = null; 
+    $scope.enrollment = {programStartDate: '', programEndDate: '', operator: $scope.defaultOperators[0]};
+   
+    $scope.searchMode = {listAll: 'LIST_ALL', freeText: 'FREE_TEXT', attributeBased: 'ATTRIBUTE_BASED'};
+    $scope.selectedSearchMode = $scope.searchMode.listAll;
+    
+    if(angular.isObject($scope.programs) && $scope.programs.length === 1){
+        $scope.selectedProgramForRelative = $scope.programs[0];        
+    } 
+    
+    if($scope.selectedProgram){
+        if($scope.selectedProgram.relatedProgram && $scope.relatedProgramRelationship){
+            angular.forEach($scope.programs, function(pr){
+                if(pr.id === $scope.selectedProgram.relatedProgram.id){
+                    $scope.selectedProgramForRelative = pr;
+                }
+            });
+        }
+        
+        if($scope.selectedProgram.relationshipType){
+            angular.forEach($scope.relationshipTypes, function(rel){
+                if(rel.id === $scope.selectedProgram.relationshipType.id){
+                    $scope.relationship.selected = rel;
+                }
+            });
+        }
+    }
+    
+    //watch for selection of relationship
+    $scope.$watch('relationship.selected', function() {        
+        if( angular.isObject($scope.relationship.selected)){
+            $scope.selectedRelationship = {aIsToB: $scope.relationship.selected.aIsToB, bIsToA: $scope.relationship.selected.bIsToA};  
+        }
+    });
+    
+    function resetFields(){
+        
+        $scope.teiForRelationship = null;
+        $scope.teiFetched = false;    
+        $scope.emptySearchText = false;
+        $scope.emptySearchAttribute = false;
+        $scope.showAdvancedSearchDiv = false;
+        $scope.showRegistrationDiv = false;  
+        $scope.showTrackedEntityDiv = false;
+        $scope.trackedEntityList = null; 
+        $scope.teiCount = null;
+
+        $scope.queryUrl = null;
+        $scope.programUrl = null;
+        $scope.attributeUrl = {url: null, hasValue: false};
+        $scope.sortColumn = {};
+    }
+    
+    //listen for selections
+    $scope.$on('relationship', function(event, args){
+        if(args.result === 'SUCCESS'){
+            var relationshipInfo = CurrentSelection.getRelationshipInfo();
+            $scope.teiForRelationship = relationshipInfo.tei;
+        }
+        
+        if(args.result === 'CANCEL'){
+            $scope.showRegistration();
+        }        
+    });
+    
+    //sortGrid
+    $scope.sortGrid = function(gridHeader){
+        if ($scope.sortColumn && $scope.sortColumn.id === gridHeader.id){
+            $scope.reverse = !$scope.reverse;
+            return;
+        }        
+        $scope.sortColumn = gridHeader;
+        if($scope.sortColumn.valueType === 'date'){
+            $scope.reverse = true;
+        }
+        else{
+            $scope.reverse = false;    
+        }
+    };
+    
+    $scope.d2Sort = function(tei){        
+        if($scope.sortColumn && $scope.sortColumn.valueType === 'date'){            
+            var d = tei[$scope.sortColumn.id];         
+            return DateUtils.getDate(d);
+        }
+        return tei[$scope.sortColumn.id];
+    };
+    
+    $scope.search = function(mode){ 
+        
+        resetFields();
+        
+        $scope.selectedSearchMode = mode;        
+   
+        if($scope.selectedProgramForRelative){
+            $scope.programUrl = 'program=' + $scope.selectedProgramForRelative.id;
+        }        
+        
+        //check search mode
+        if( $scope.selectedSearchMode === $scope.searchMode.freeText ){ 
+            
+            if(!$scope.searchText.value){                
+                $scope.emptySearchText = true;
+                $scope.teiFetched = false;   
+                $scope.teiCount = null;
+                return;
+            }       
+
+            $scope.queryUrl = 'query=LIKE:' + $scope.searchText.value;                     
+        }
+        
+        if( $scope.selectedSearchMode === $scope.searchMode.attributeBased ){            
+            $scope.searchText.value = null;
+            $scope.attributeUrl = EntityQueryFactory.getAttributesQuery($scope.attributes, $scope.enrollment);
+            
+            if(!$scope.attributeUrl.hasValue && !$scope.selectedProgramForRelative){
+                $scope.emptySearchAttribute = true;
+                $scope.teiFetched = false;   
+                $scope.teiCount = null;
+                return;
+            }
+        }
+        
+        $scope.fetchTei();
+    };
+    
+    $scope.fetchTei = function(){
+
+        //get events for the specified parameters
+        TEIService.search($scope.selectedOrgUnit.id, 
+                                            $scope.selectedOuMode.name,
+                                            $scope.queryUrl,
+                                            $scope.programUrl,
+                                            $scope.attributeUrl.url,
+                                            $scope.pager,
+                                            true).then(function(data){
+            //$scope.trackedEntityList = data;            
+            if(data.rows){
+                $scope.teiCount = data.rows.length;
+            }                    
+            
+            if( data.metaData.pager ){
+                $scope.pager = data.metaData.pager;
+                $scope.pager.toolBarDisplay = 5;
+
+                Paginator.setPage($scope.pager.page);
+                Paginator.setPageCount($scope.pager.pageCount);
+                Paginator.setPageSize($scope.pager.pageSize);
+                Paginator.setItemCount($scope.pager.total);                    
+            }
+            
+            //process tei grid
+            $scope.trackedEntityList = TEIGridService.format(data,false, $scope.optionSets, invalidTeis);
+            $scope.showTrackedEntityDiv = true;
+            $scope.teiFetched = true;
+            
+            if(!$scope.sortColumn.id){                                      
+                $scope.sortGrid({id: 'created', name: $translate('registration_date'), valueType: 'date', displayInListNoProgram: false, showFilter: false, show: false});
+            }
+            
+        });
+    };
+    
+    //set attributes as per selected program
+    $scope.setAttributesForSearch = function(program){
+        
+        $scope.selectedProgramForRelative = program;
+        AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
+            $scope.attributes = atts;
+            $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
+            $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
+        });
+        
+        $scope.search( $scope.selectedSearchMode );        
+    }; 
+    
+    $scope.setAttributesForSearch( $scope.selectedProgramForRelative );
+    
+    $scope.jumpToPage = function(){
+        if($scope.pager && $scope.pager.page && $scope.pager.pageCount && $scope.pager.page > $scope.pager.pageCount){
+            $scope.pager.page = $scope.pager.pageCount;
+        }
+        
+        $scope.search($scope.selectedSearchMode);
+    };
+    
+    $scope.resetPageSize = function(){
+        $scope.pager.page = 1;        
+        $scope.search($scope.selectedSearchMode);
+    };
+    
+    $scope.getPage = function(page){
+        $scope.pager.page = page;
+        $scope.search($scope.selectedSearchMode);
+    };
+    
+    $scope.generateAttributeFilters = function(attributes){
+
+        angular.forEach(attributes, function(attribute){
+            if(attribute.valueType === 'number' || attribute.valueType === 'date'){
+                attribute.operator = $scope.defaultOperators[0];
+            }
+        });
+                    
+        return attributes;
+    };
+
+    //generate grid columns from teilist attributes
+    $scope.generateGridColumns = function(attributes){
+
+        var columns = attributes ? angular.copy(attributes) : [];
+       
+        //also add extra columns which are not part of attributes (orgunit for example)
+        columns.push({id: 'orgUnitName', name: 'Organisation unit', type: 'TEXT', displayInListNoProgram: false});
+        columns.push({id: 'created', name: 'Registration date', type: 'TEXT', displayInListNoProgram: false});
+        
+        //generate grid column for the selected program/attributes
+        angular.forEach(columns, function(column){
+            if(column.id === 'orgUnitName' && $scope.selectedOuMode.name !== 'SELECTED'){
+                column.show = true;
+            }
+            
+            if(column.displayInListNoProgram){
+                column.show = true;
+            }           
+           
+            if(column.type === 'date'){
+                $scope.filterText[column.id]= {start: '', end: ''};
+            }
+        });        
+        return columns;        
+    };   
+    
+    $scope.showHideSearch = function(simpleSearch){
+        if(simpleSearch){
+            $scope.showAdvancedSearchDiv = false;
+        }
+        else{
+            $scope.showAdvancedSearchDiv = !$scope.showAdvancedSearchDiv;
+        }
+        
+        if($scope.showAdvancedSearchDiv){
+            $scope.showTrackedEntityDiv = false;
+        }
+        else{
+            $scope.showTrackedEntityDiv = true;
+        }
+    };
+    
+    $scope.showRegistration = function(){
+        $scope.showRegistrationDiv = !$scope.showRegistrationDiv;
+        
+        if($scope.showRegistrationDiv){
+            $scope.showTrackedEntityDiv = false;
+            $timeout(function() {
+                var mainTei = angular.copy($scope.selectedTei); 
+                angular.forEach(mainTei.attributes, function(att){
+                    mainTei[att.attribute] = att.value;
+                });
+                $rootScope.$broadcast('registrationWidget', {registrationMode: 'RELATIONSHIP', mainTei: mainTei, relativeProgram: $scope.selectedProgramForRelative});
+            }, 200);
+        }
+        else{
+            $scope.showTrackedEntityDiv = true;            
+        }        
+    };
+    
+    $scope.close = function () {
+        $modalInstance.close($scope.selectedTei.relationships ? $scope.selectedTei.relationships : []);
+        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
+    };
+    
+    $scope.setRelationshipSides = function(side){
+        if(side === 'A'){            
+            $scope.selectedRelationship.bIsToA = $scope.selectedRelationship.aIsToB === $scope.relationship.selected.aIsToB ? $scope.relationship.selected.bIsToA : $scope.relationship.selected.aIsToB;
+        }
+        if(side === 'B'){
+            $scope.selectedRelationship.aIsToB = $scope.selectedRelationship.bIsToA === $scope.relationship.selected.bIsToA ? $scope.relationship.selected.aIsToB : $scope.relationship.selected.bIsToA;
+        }
+    };
+    
+    $scope.assignRelationship = function(relativeTei){
+        $scope.teiForRelationship = relativeTei;
+        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
+    };
+    
+    
+    $scope.back = function(){
+        $scope.teiForRelationship = null;
+        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
+    };
+    
+    $scope.addRelationship = function(){
+        if($scope.selectedTei && $scope.teiForRelationship && $scope.relationship.selected){            
+            var tei = angular.copy($scope.selectedTei);
+            var relationship = {};
+            relationship.relationship = $scope.relationship.selected.id;
+            relationship.displayName = $scope.relationship.selected.name;
+            relationship.relative = {};
+            
+            
+            relationship.trackedEntityInstanceA = $scope.selectedRelationship.aIsToB === $scope.relationship.selected.aIsToB ? $scope.selectedTei.trackedEntityInstance : $scope.teiForRelationship.id;
+            relationship.trackedEntityInstanceB = $scope.selectedRelationship.bIsToA === $scope.relationship.selected.bIsToA ? $scope.teiForRelationship.id : $scope.selectedTei.trackedEntityInstance;
+            
+            tei.relationships = [];
+            angular.forEach($scope.selectedTei.relationships, function(rel){
+                tei.relationships.push({relationship: rel.relationship, displayName: rel.displayName, trackedEntityInstanceA: rel.trackedEntityInstanceA, trackedEntityInstanceB: rel.trackedEntityInstanceB});
+            });
+            tei.relationships.push(relationship);
+            
+            TEIService.update(tei, $scope.optionSets, $scope.attributesById).then(function(response){
+                if(response.response && response.response.status !== 'SUCCESS'){//update has failed
+                    var dialogOptions = {
+                            headerText: 'relationship_error',
+                            bodyText: response.message
+                        };
+                    DialogService.showDialog({}, dialogOptions);
+                    return;
+                }
+                
+                relationship.relative.processed = true;
+                relationship.relative.attributes = $scope.teiForRelationship;
+                
+                if($scope.selectedTei.relationships){
+                    $scope.selectedTei.relationships.push(relationship);
+                }
+                else{
+                    $scope.selectedTei.relationships = [relationship];
+                }
+                
+                $modalInstance.close($scope.selectedTei.relationships);                
+            });
+        }        
+    };
+    
+    //Get orgunits for the logged in user
+    OrgUnitFactory.getSearchTreeRoot().then(function(response) {  
+        $scope.orgUnits = response.organisationUnits;
+        angular.forEach($scope.orgUnits, function(ou){
+            ou.show = true;
+            angular.forEach(ou.children, function(o){                    
+                o.hasChildren = o.children && o.children.length > 0 ? true : false;
+            });            
+        });
+    });
+    
+    //expand/collapse of search orgunit tree
+    $scope.expandCollapse = function(orgUnit) {
+        if( orgUnit.hasChildren ){            
+            //Get children for the selected orgUnit
+            OrgUnitFactory.get(orgUnit.id).then(function(ou) {                
+                orgUnit.show = !orgUnit.show;
+                orgUnit.hasChildren = false;
+                orgUnit.children = ou.organisationUnits[0].children;                
+                angular.forEach(orgUnit.children, function(ou){                    
+                    ou.hasChildren = ou.children && ou.children.length > 0 ? true : false;
+                });                
+            });           
+        }
+        else{
+            orgUnit.show = !orgUnit.show;   
+        }        
+    };
+   
+    //load programs for the selected orgunit (from tree)
+    $scope.setSelectedSearchingOrgUnit = function(orgUnit){    
+        $scope.selectedSearchingOrgUnit = orgUnit;
+    };
+});

=== added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add.html'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add.html	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/components/teiadd/tei-add.html	2015-09-23 14:06:13 +0000
@@ -0,0 +1,121 @@
+<div class="modal-header page">
+    <h2>{{teiAddLabel}}</h2>
+</div>
+<div class="modal-body">
+    <div class='row' ng-if="addingRelationship">
+        <div class='col-md-12'>
+            <select ng-model="relationship.selected"
+                    class="form-control"
+                    ng-options="rel as rel.name for rel in relationshipTypes | orderBy: 'name'"
+                    ng-disabled="relatedProgramRelationship">
+                <option value="">{{'please_select_a_relationship'| translate}}</option>
+            </select>
+        </div>
+    </div>
+
+    <div class="row" ng-if="relationship.selected || !addingRelationship">
+        <hr>
+        <div class="col-md-4" ng-if="addingRelationship">
+            <select name="foo" 
+                    ng-model="selectedRelationship.aIsToB" 
+                    class="form-control" 
+                    ng-change="setRelationshipSides('A')"
+                    ng-disabled="selectedProgramForRelative && selectedProgram.relatedProgram && relatedProgramRelationship">
+                <option>{{relationship.selected.aIsToB}}</option>
+                <option>{{relationship.selected.bIsToA}}</option>
+            </select>
+            <div class='relationship-container'>
+                <table class="table table-striped table-compact table-borderless">
+                    <tr ng-repeat="attribute in selectedTeiForDisplay.attributes">
+                        <td>
+                            {{attribute.displayName}}
+                        </td>
+                        <td>
+                            {{attribute.value}}                                                                                                  
+                        </td>
+                    </tr>           
+                </table>
+            </div>
+        </div>
+        
+        <div ng-class="{true: 'col-md-8 pull-right', false: 'col-sm-12'} [addingRelationship]">
+            
+            <div ng-if="addingRelationship">
+                <select name="foo" 
+                        ng-model="selectedRelationship.bIsToA" 
+                        class="form-control" 
+                        ng-change="setRelationshipSides('B')"
+                        ng-disabled="selectedProgramForRelative && selectedProgram.relatedProgram && relatedProgramRelationship">    
+                    <option>{{relationship.selected.aIsToB}}</option>
+                    <option>{{relationship.selected.bIsToA}}</option>
+                </select>                
+            </div>            
+            
+            <div class='relationship-container' ng-class="{true: '', false: 'col-sm-6'} [addingRelationship]" ng-if="teiForRelationship">
+                <button class="btn btn-warning" type="button" ng-click="back()">{{'back' | translate}}</button>
+                <table class="table table-striped table-compact table-borderless">
+                    <tr ng-repeat="gridColumn in gridColumns">
+                        <td>
+                            {{gridColumn.name}}
+                        </td>
+                        <td >                                                
+                            {{teiForRelationship[gridColumn.id]}}                                                
+                        </td> 
+                    </tr>
+                </table>                
+            </div>
+            
+            <div class='relationship-container' ng-if="!teiForRelationship">
+
+                <div class="row">                    
+                    <div class="col-sm-4 vertical-spacing">
+                        <select ng-model="selectedProgramForRelative"
+                                class="form-control"
+                                ng-disabled="programs.length < 1 || (selectedProgramForRelative && selectedProgram.relatedProgram && relatedProgramRelationship)"
+                                ng-options="program as program.name for program in programs | orderBy: 'name'" 
+                                ng-change="setAttributesForSearch(selectedProgramForRelative)">
+                            <option value="">{{'please_select_a_program'| translate}}</option>
+                        </select>                
+                    </div>
+                    <div class="input-group col-sm-8 vertical-spacing">
+                        <input type="text" placeholder="{{'type_your_search_criteria_here'| translate}}" ng-model="searchText.value" d2-enter="search(searchMode.freeText)" class="form-control expanded" ng-class="{true: 'invalid - input'} [!searchText && emptySearchText]" ng-focus="showHideSearch(true)">
+                        <div class="input-group-btn">
+                            <button class="btn btn-default without-border-radius trim" type="button" title="{{'advanced_search'| translate}}" ng-click="showHideSearch(false)"><i class="fa fa-caret-down"></i></button>
+                            <button class="btn btn-primary without-border-radius trim" type="button" title="{{'search'| translate}}" ng-click="search(searchMode.freeText)"><i class="fa fa-search"></i></button>                            
+                            <button class="btn btn-default without-border-radius trim" type="button" title="{{'list_all'| translate}}" ng-disabled="showRegistrationDiv" ng-click="search(searchMode.listAll)"><i class="fa fa-list"></i></button>
+                            <button class="btn btn-success trim" type="button" title="{{'register'| translate}}" ng-click="showRegistration()"><i class="fa fa-plus-square"></i></button>                            
+                        </div>                
+                    </div>                    
+                </div>
+
+                <div ng-if="showAdvancedSearchDiv">
+                    <div ng-include="'views/advanced-search.html'"></div>     
+                    <span>&nbsp;</span>
+                </div>
+
+                <!-- entity grid begins -->
+                <i ng-if="!teiFetched" class="fa fa-spinner fa-spin fa-2x"></i>
+                <div class="row col-sm-12" ng-if="!showRegistrationDiv" ng-include="'views/tei.html'"></div>
+                <!-- entity grid ends -->
+
+                <!--- Error display for search begins -->
+                <div class="row" ng-if="emptySearchAttribute || !searchText.value && emptySearchText">
+                    <div class="col-md-12 vertical-spacing">
+                        <div class="alert alert-danger">{{'search_input_required'| translate}}</div>         
+                    </div>
+                </div>
+                <!--- Error display for search ends -->
+                
+                <div ng-show="showRegistrationDiv">
+                    <!--<div ng-include="'components/relationship/registration.html'"></div>-->
+                    <div ng-include="'components/registration/registration.html'"></div>
+                    <span>&nbsp;</span>
+                </div>
+            </div>
+        </div>        
+    </div>
+</div>
+<div class="modal-footer">        
+    <button class="btn btn-primary trim" data-ng-click="addRelationship()" ng-disabled='!teiForRelationship'>{{'save'| translate}}</button>
+    <button class="btn btn-default" data-ng-click="close()">{{'close'| translate}}</button>    
+</div> 
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2015-09-23 12:05:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/i18n/i18n_app.properties	2015-09-23 14:06:13 +0000
@@ -75,6 +75,7 @@
 find=Find
 edit=Edit
 edit_profile=Edit profile
+tracker_associate=Tracker associate
 association=Manage associations
 change_location=Manage location
 details_history=Details/history

=== 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	2015-09-23 10:24:45 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/index.html	2015-09-23 14:06:13 +0000
@@ -104,7 +104,8 @@
         <script type="text/javascript" src="components/report/overdue-events-controller.js"></script>
         <script type="text/javascript" src="components/report/upcoming-events-controller.js"></script>
         <script type="text/javascript" src="components/selected/selected-controller.js"></script>
-        <script type="text/javascript" src="components/relationship/relationship-controller.js"></script>        
+        <script type="text/javascript" src="components/relationship/relationship-controller.js"></script>
+        <script type="text/javascript" src="components/teiadd/tei-add-controller.js"></script>
         <script type="text/javascript" src="components/profile/profile-controller.js"></script>        
         <script type="text/javascript" src="components/notes/notes-controller.js"></script>
         <script type="text/javascript" src="components/rulebound/rulebound-controller.js"></script>

=== added file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tei-add-controller.js'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tei-add-controller.js	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/scripts/tei-add-controller.js	2015-09-23 14:06:13 +0000
@@ -0,0 +1,393 @@
+/* global trackerCapture, angular */
+
+trackerCapture.controller('TEIAddController', 
+    function($scope, 
+            $rootScope,
+            $translate,
+            $timeout,
+            DateUtils,
+            CurrentSelection,
+            OperatorFactory,
+            AttributesFactory,
+            EntityQueryFactory,
+            TEIService,
+            TEIGridService,
+            DialogService,
+            Paginator,
+            SessionStorageService,
+            $modalInstance, 
+            relationshipTypes,
+            selectedProgram,
+            relatedProgramRelationship,
+            selections,
+            selectedTei){
+    
+    $scope.relationshipTypes = relationshipTypes;
+    $scope.selectedProgram = selectedProgram;
+    $scope.relatedProgramRelationship = relatedProgramRelationship;
+    $scope.selectedTei = selectedTei;
+    $scope.programs = selections.prs;
+    $scope.attributesById = CurrentSelection.getAttributesById();
+    
+    $scope.selectedRelationship = {};
+    $scope.relationship = {};
+    
+    var invalidTeis = [];
+    invalidTeis.push($scope.selectedTei.trackedEntityInstance);
+    angular.forEach($scope.selectedTei.relationships, function(rel){
+        invalidTeis.push(rel.trackedEntityInstanceB);
+    });
+
+    //Selections
+    $scope.selectedOrgUnit = SessionStorageService.get('SELECTED_OU');
+    $scope.optionSets = selections.optionSets;
+    $scope.selectedTeiForDisplay = angular.copy($scope.selectedTei);
+    $scope.ouModes = [{name: 'SELECTED'}, {name: 'CHILDREN'}, {name: 'DESCENDANTS'}, {name: 'ACCESSIBLE'}];         
+    $scope.selectedOuMode = $scope.ouModes[0];
+    
+    //Paging
+    $scope.pager = {pageSize: 50, page: 1, toolBarDisplay: 5}; 
+    
+    //Searching
+    $scope.showAdvancedSearchDiv = false;
+    $scope.searchText = {value: null};
+    $scope.emptySearchText = false;
+    $scope.searchFilterExists = false;   
+    $scope.defaultOperators = OperatorFactory.defaultOperators;
+    $scope.boolOperators = OperatorFactory.boolOperators;
+    
+    $scope.trackedEntityList = null; 
+    $scope.enrollment = {programStartDate: '', programEndDate: '', operator: $scope.defaultOperators[0]};
+   
+    $scope.searchMode = {listAll: 'LIST_ALL', freeText: 'FREE_TEXT', attributeBased: 'ATTRIBUTE_BASED'};
+    $scope.selectedSearchMode = $scope.searchMode.listAll;
+    
+    if(angular.isObject($scope.programs) && $scope.programs.length === 1){
+        $scope.selectedProgramForRelative = $scope.programs[0];        
+    } 
+    
+    if($scope.selectedProgram){
+        if($scope.selectedProgram.relatedProgram && $scope.relatedProgramRelationship){
+            angular.forEach($scope.programs, function(pr){
+                if(pr.id === $scope.selectedProgram.relatedProgram.id){
+                    $scope.selectedProgramForRelative = pr;
+                }
+            });
+        }
+        
+        if($scope.selectedProgram.relationshipType){
+            angular.forEach($scope.relationshipTypes, function(rel){
+                if(rel.id === $scope.selectedProgram.relationshipType.id){
+                    $scope.relationship.selected = rel;
+                }
+            });
+        }
+    }
+    
+    //watch for selection of relationship
+    $scope.$watch('relationship.selected', function() {        
+        if( angular.isObject($scope.relationship.selected)){
+            $scope.selectedRelationship = {aIsToB: $scope.relationship.selected.aIsToB, bIsToA: $scope.relationship.selected.bIsToA};  
+        }
+    });
+    
+    function resetFields(){
+        
+        $scope.teiForRelationship = null;
+        $scope.teiFetched = false;    
+        $scope.emptySearchText = false;
+        $scope.emptySearchAttribute = false;
+        $scope.showAdvancedSearchDiv = false;
+        $scope.showRegistrationDiv = false;  
+        $scope.showTrackedEntityDiv = false;
+        $scope.trackedEntityList = null; 
+        $scope.teiCount = null;
+
+        $scope.queryUrl = null;
+        $scope.programUrl = null;
+        $scope.attributeUrl = {url: null, hasValue: false};
+        $scope.sortColumn = {};
+    }
+    
+    //listen for selections
+    $scope.$on('relationship', function(event, args){
+        if(args.result === 'SUCCESS'){
+            var relationshipInfo = CurrentSelection.getRelationshipInfo();
+            $scope.teiForRelationship = relationshipInfo.tei;
+        }
+        
+        if(args.result === 'CANCEL'){
+            $scope.showRegistration();
+        }        
+    });
+    
+    //sortGrid
+    $scope.sortGrid = function(gridHeader){
+        if ($scope.sortColumn && $scope.sortColumn.id === gridHeader.id){
+            $scope.reverse = !$scope.reverse;
+            return;
+        }        
+        $scope.sortColumn = gridHeader;
+        if($scope.sortColumn.valueType === 'date'){
+            $scope.reverse = true;
+        }
+        else{
+            $scope.reverse = false;    
+        }
+    };
+    
+    $scope.d2Sort = function(tei){        
+        if($scope.sortColumn && $scope.sortColumn.valueType === 'date'){            
+            var d = tei[$scope.sortColumn.id];         
+            return DateUtils.getDate(d);
+        }
+        return tei[$scope.sortColumn.id];
+    };
+    
+    $scope.search = function(mode){ 
+        
+        resetFields();
+        
+        $scope.selectedSearchMode = mode;        
+   
+        if($scope.selectedProgramForRelative){
+            $scope.programUrl = 'program=' + $scope.selectedProgramForRelative.id;
+        }        
+        
+        //check search mode
+        if( $scope.selectedSearchMode === $scope.searchMode.freeText ){ 
+            
+            if(!$scope.searchText.value){                
+                $scope.emptySearchText = true;
+                $scope.teiFetched = false;   
+                $scope.teiCount = null;
+                return;
+            }       
+
+            $scope.queryUrl = 'query=LIKE:' + $scope.searchText.value;                     
+        }
+        
+        if( $scope.selectedSearchMode === $scope.searchMode.attributeBased ){            
+            $scope.searchText.value = null;
+            $scope.attributeUrl = EntityQueryFactory.getAttributesQuery($scope.attributes, $scope.enrollment);
+            
+            if(!$scope.attributeUrl.hasValue && !$scope.selectedProgramForRelative){
+                $scope.emptySearchAttribute = true;
+                $scope.teiFetched = false;   
+                $scope.teiCount = null;
+                return;
+            }
+        }
+        
+        $scope.fetchTei();
+    };
+    
+    $scope.fetchTei = function(){
+
+        //get events for the specified parameters
+        TEIService.search($scope.selectedOrgUnit.id, 
+                                            $scope.selectedOuMode.name,
+                                            $scope.queryUrl,
+                                            $scope.programUrl,
+                                            $scope.attributeUrl.url,
+                                            $scope.pager,
+                                            true).then(function(data){
+            //$scope.trackedEntityList = data;            
+            if(data.rows){
+                $scope.teiCount = data.rows.length;
+            }                    
+            
+            if( data.metaData.pager ){
+                $scope.pager = data.metaData.pager;
+                $scope.pager.toolBarDisplay = 5;
+
+                Paginator.setPage($scope.pager.page);
+                Paginator.setPageCount($scope.pager.pageCount);
+                Paginator.setPageSize($scope.pager.pageSize);
+                Paginator.setItemCount($scope.pager.total);                    
+            }
+            
+            //process tei grid
+            $scope.trackedEntityList = TEIGridService.format(data,false, $scope.optionSets, invalidTeis);
+            $scope.showTrackedEntityDiv = true;
+            $scope.teiFetched = true;
+            
+            if(!$scope.sortColumn.id){                                      
+                $scope.sortGrid({id: 'created', name: $translate('registration_date'), valueType: 'date', displayInListNoProgram: false, showFilter: false, show: false});
+            }
+            
+        });
+    };
+    
+    //set attributes as per selected program
+    $scope.setAttributesForSearch = function(program){
+        
+        $scope.selectedProgramForRelative = program;
+        AttributesFactory.getByProgram($scope.selectedProgramForRelative).then(function(atts){
+            $scope.attributes = atts;
+            $scope.attributes = $scope.generateAttributeFilters($scope.attributes);
+            $scope.gridColumns = $scope.generateGridColumns($scope.attributes);
+        });
+        
+        $scope.search( $scope.selectedSearchMode );        
+    }; 
+    
+    $scope.setAttributesForSearch( $scope.selectedProgramForRelative );
+    
+    $scope.jumpToPage = function(){
+        if($scope.pager && $scope.pager.page && $scope.pager.pageCount && $scope.pager.page > $scope.pager.pageCount){
+            $scope.pager.page = $scope.pager.pageCount;
+        }
+        
+        $scope.search($scope.selectedSearchMode);
+    };
+    
+    $scope.resetPageSize = function(){
+        $scope.pager.page = 1;        
+        $scope.search($scope.selectedSearchMode);
+    };
+    
+    $scope.getPage = function(page){
+        $scope.pager.page = page;
+        $scope.search($scope.selectedSearchMode);
+    };
+    
+    $scope.generateAttributeFilters = function(attributes){
+
+        angular.forEach(attributes, function(attribute){
+            if(attribute.valueType === 'number' || attribute.valueType === 'date'){
+                attribute.operator = $scope.defaultOperators[0];
+            }
+        });
+                    
+        return attributes;
+    };
+
+    //generate grid columns from teilist attributes
+    $scope.generateGridColumns = function(attributes){
+
+        var columns = attributes ? angular.copy(attributes) : [];
+       
+        //also add extra columns which are not part of attributes (orgunit for example)
+        columns.push({id: 'orgUnitName', name: 'Organisation unit', type: 'TEXT', displayInListNoProgram: false});
+        columns.push({id: 'created', name: 'Registration date', type: 'TEXT', displayInListNoProgram: false});
+        
+        //generate grid column for the selected program/attributes
+        angular.forEach(columns, function(column){
+            if(column.id === 'orgUnitName' && $scope.selectedOuMode.name !== 'SELECTED'){
+                column.show = true;
+            }
+            
+            if(column.displayInListNoProgram){
+                column.show = true;
+            }           
+           
+            if(column.type === 'date'){
+                $scope.filterText[column.id]= {start: '', end: ''};
+            }
+        });        
+        return columns;        
+    };   
+    
+    $scope.showHideSearch = function(simpleSearch){
+        if(simpleSearch){
+            $scope.showAdvancedSearchDiv = false;
+        }
+        else{
+            $scope.showAdvancedSearchDiv = !$scope.showAdvancedSearchDiv;
+        }
+        
+        if($scope.showAdvancedSearchDiv){
+            $scope.showTrackedEntityDiv = false;
+        }
+        else{
+            $scope.showTrackedEntityDiv = true;
+        }
+    };
+    
+    $scope.showRegistration = function(){
+        $scope.showRegistrationDiv = !$scope.showRegistrationDiv;
+        
+        if($scope.showRegistrationDiv){
+            $scope.showTrackedEntityDiv = false;
+            $timeout(function() {
+                var mainTei = angular.copy($scope.selectedTei); 
+                angular.forEach(mainTei.attributes, function(att){
+                    mainTei[att.attribute] = att.value;
+                });
+                $rootScope.$broadcast('registrationWidget', {registrationMode: 'RELATIONSHIP', mainTei: mainTei, relativeProgram: $scope.selectedProgramForRelative});
+            }, 200);
+        }
+        else{
+            $scope.showTrackedEntityDiv = true;            
+        }        
+    };
+    
+    $scope.close = function () {
+        $modalInstance.close($scope.selectedTei.relationships ? $scope.selectedTei.relationships : []);
+        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
+    };
+    
+    $scope.setRelationshipSides = function(side){
+        if(side === 'A'){            
+            $scope.selectedRelationship.bIsToA = $scope.selectedRelationship.aIsToB === $scope.relationship.selected.aIsToB ? $scope.relationship.selected.bIsToA : $scope.relationship.selected.aIsToB;
+        }
+        if(side === 'B'){
+            $scope.selectedRelationship.aIsToB = $scope.selectedRelationship.bIsToA === $scope.relationship.selected.bIsToA ? $scope.relationship.selected.aIsToB : $scope.relationship.selected.bIsToA;
+        }
+    };
+    
+    $scope.assignRelationship = function(relativeTei){
+        $scope.teiForRelationship = relativeTei;
+        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
+    };
+    
+    
+    $scope.back = function(){
+        $scope.teiForRelationship = null;
+        $rootScope.showAddRelationshipDiv = !$rootScope.showAddRelationshipDiv;
+    };
+    
+    $scope.addRelationship = function(){
+        if($scope.selectedTei && $scope.teiForRelationship && $scope.relationship.selected){            
+            var tei = angular.copy($scope.selectedTei);
+            var relationship = {};
+            relationship.relationship = $scope.relationship.selected.id;
+            relationship.displayName = $scope.relationship.selected.name;
+            relationship.relative = {};
+            
+            
+            relationship.trackedEntityInstanceA = $scope.selectedRelationship.aIsToB === $scope.relationship.selected.aIsToB ? $scope.selectedTei.trackedEntityInstance : $scope.teiForRelationship.id;
+            relationship.trackedEntityInstanceB = $scope.selectedRelationship.bIsToA === $scope.relationship.selected.bIsToA ? $scope.teiForRelationship.id : $scope.selectedTei.trackedEntityInstance;
+            
+            tei.relationships = [];
+            angular.forEach($scope.selectedTei.relationships, function(rel){
+                tei.relationships.push({relationship: rel.relationship, displayName: rel.displayName, trackedEntityInstanceA: rel.trackedEntityInstanceA, trackedEntityInstanceB: rel.trackedEntityInstanceB});
+            });
+            tei.relationships.push(relationship);
+            
+            TEIService.update(tei, $scope.optionSets, $scope.attributesById).then(function(response){
+                if(response.response && response.response.status !== 'SUCCESS'){//update has failed
+                    var dialogOptions = {
+                            headerText: 'relationship_error',
+                            bodyText: response.message
+                        };
+                    DialogService.showDialog({}, dialogOptions);
+                    return;
+                }
+                
+                relationship.relative.processed = true;
+                relationship.relative.attributes = $scope.teiForRelationship;
+                
+                if($scope.selectedTei.relationships){
+                    $scope.selectedTei.relationships.push(relationship);
+                }
+                else{
+                    $scope.selectedTei.relationships = [relationship];
+                }
+                
+                $modalInstance.close($scope.selectedTei.relationships);                
+            });
+        }        
+    };
+});

=== modified file 'dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css'
--- dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2015-09-23 12:05:11 +0000
+++ dhis-2/dhis-web/dhis-web-apps/src/main/webapp/dhis-web-tracker-capture/styles/style.css	2015-09-23 14:06:13 +0000
@@ -526,7 +526,6 @@
 div#searchOuTree accordion>.panel-group>.panel-default>.panel-heading{
     background-color: #ffffff;
     padding: 10px 5px 10px 5px;
-    //padding: 5px 9px 5px 5px;
 }
 
 div#searchOuTree h4{