Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The view for this page is large, and will require some AngularJS knowledge to understand (TO DO describe this better):

Code Block
languagexml
titlerelationships/list.gsp (in coreapps module)
<%
    // Nearly every page you write should do this, to get the standard reference application decoration and includes
    ui.decorateWith("appui", "standardEmrPage")
 
   ui.includeJavascript("uicommons", "angular.js") // include angular and angular-ui
    ui.includeJavascript("uicommons", "angular-resource.min.js")
    ui.includeJavascript("uicommons", "angular-commonresource.min.js")
    ui.includeJavascript("uicommons", "angular-ui/ui-bootstrap-tpls-0.6.0.min.js")
 
    // we use the following OpenMRS angular services and directives
    ui.includeJavascript("uicommons", "services/relationshipServiceangular-common.js")
    ui.includeJavascript("uicommons", "services/relationshipTypeServicerelationshipService.js")
    ui.includeJavascript("uicommons", "services/personServicerelationshipTypeService.js")
    ui.includeJavascript("uicommons", "directivesservices/select-personpersonService.js")
    ui.includeJavascript("coreappsuicommons", "relationshipsdirectives/relationshipsselect-person.js")
%> 
<script type="text/javascript">   // custom varJS breadcrumbsand =CSS [for this page
      { icon: "icon-home", link: '/' + OPENMRS_CONTEXT_PATH + '/index.htm' },
        { label: "${ ui.format(patient.patient.familyName) }, ${ ui.format(patient.patient.givenName) }" ,
      ui.includeJavascript("coreapps", "relationships/relationships.js")
    ui.includeCss("coreapps", "relationships/relationships.css")
%>
 
<!-- Configuring breadcrumbs; you'd typically copy-paste this from another page and change the last item in the list -->
<script type="text/javascript">
    var breadcrumbs = [
     link:   '${ui.pageLink("coreapps", "clinicianfacing/patient{ icon: "icon-home", [patientIdlink: patient.patient.id])}''/' + OPENMRS_CONTEXT_PATH + '/index.htm' },
        { label: "${ ui.escapeJs(patient.patient.familyName) }, ${ ui.messageescapeJs("coreappspatient.task.relationships.label"))patient.givenName) }" },
    ] </script> <style type="text/css">     .relationshiplink: '${ui.pageLink("coreapps", "clinicianfacing/patient", [patientId: patient.patient.id])}'},
     position: relative;  { label: "${ ui.escapeJs(ui.message("coreapps.task.relationships.label")) }" }
 border: 1px solid #DADADA;]
</script>
 
<!-- Include the standard patient header padding:before 5pxwe 25pxget 5pxto 5px;the specifics of this page }-->
${    .relationship i {
        position: absolute;
        right: 0px;
 ui.includeFragment("coreapps", "patientHeader", [ patient: patient.patient ]) }
 
<!-- Your page should have a title -->
<h2>${ ui.message("coreapps.task.relationships.label") }</h2>
<div id="relationships-app" ng-controller="PersonRelationshipsCtrl" ng-init="init('${ patient.patient.uuid }')">
    <div  cursor: pointer;ng-show="addDialogMode" class="dialog" id="add-relationship-dialog">
    }    <div .dialog {class="dialog-header">
         position: absolute;         z-index: 999;
<%= ui.message("coreapps.relationships.add.header", "{{ addDialogOtherLabel }}") %>
   }     .add-confirm-spacer {</div>
        <div min-height: 110px;class="dialog-content">
       } </style> ${ ui.includeFragment("coreapps", "patientHeader", [<div>
patient: patient.patient ]) } <h2>${ ui            <label>
                    <%= ui.message("coreapps.taskrelationships.relationshipsadd.labelchoose") }</h2>
<div id="relationships-app" ng-controller="PersonRelationshipsCtrl" ng-init="init('${ , "{{ addDialogOtherLabel }}") %>
                </label>
                <select-person ng-model="otherPerson" exclude-person="${ patient.patient.uuid }')" />
    <div ng-show="addDialogMode" class="dialog" id="add-relationship-dialog">        </div>
            <div class="add-confirm-spacer">
                <div ng-show="otherPerson" >
                    <h3>${ ui.message("coreapps.relationships.add.confirm") }</h3>
                    <p>{{ addDialogThisLabel }}: ${ ui.format(patient.patient) } ${ ui.message("coreapps.relationships.add.thisPatient") }</p>
                    <p>{{ addDialogOtherLabel }}: {{ otherPerson.display }}</p>
                </div>
            </div>
            <div>
                <button class="confirm right" ng-disabled="!otherPerson" ng-click="doAddRelationship()">${ ui.message("uicommons.save") }</button>
                <button class="cancel" ng-click="cancelAddRelationship()">${ ui.message("uicommons.cancel") }</button>
            </div>
        </div>
    </div>
    <div ng-show="relationshipToDelete" class="dialog" id="delete-relationship-dialog">
        <div class="dialog-header">${ ui.message("coreapps.relationships.delete.header") }</div>
        <div class="dialog-content">
            <form>
                ${ ui.message("coreapps.relationships.delete.title") }
                <p>
                    <label>{{ relType(relationshipToDelete).aIsToB }}</label>
                    {{ relationshipToDelete.personA.display }}
                </p>
                <p>
                    <label>{{ relType(relationshipToDelete).bIsToA }}</label>
                    {{ relationshipToDelete.personB.display }}
                </p>
                <button class="confirm right" ng-click="doDeleteRelationship(relationshipToDelete)">${ ui.message("uicommons.delete") }</button>
                <button class="cancel" ng-click="cancelDeleteRelationship(relationshipToDelete)">${ ui.message("uicommons.cancel") }</button>
            </form>
        </div>
    </div>
    <form id="existing-relationships">
        <div ng-repeat="relType in relationshipTypes">
            <p>
                <label>{{ relType.aIsToB }}</label>
                <span ng-repeat="rel in relationshipsByType(relType, 'A')" class="relationship">
                    {{ rel.personA.display }}
                    <a ng-click="showDeleteDialog(rel)">
                        <i class="small icon-remove"></i>
                    </a>
                </span>
                <span ng-show="relType.aIsToB == relType.bIsToA" ng-repeat="rel in relationshipsByType(relType, 'B')" class="relationship">
                    {{ rel.personB.display }}
                    <a ng-click="showDeleteDialog(rel)">
                        <i class="small icon-remove"></i>
                    </a>
                </span>
                <a ng-click="showAddDialog(relType, 'A')">
                    <i class="small icon-plus-sign"></i>
                </a>
            </p>
            <p ng-hide="relType.aIsToB == relType.bIsToA">
                <label>{{ relType.bIsToA }}</label>
                <span ng-repeat="rel in relationshipsByType(relType, 'B')" class="relationship">
                    {{ rel.personB.display }}
                    <a ng-click="showDeleteDialog(rel)">
                        <i class="small icon-remove"></i>
                    </a>
                </span>
                <a ng-click="showAddDialog(relType, 'B')">
                    <i class="small icon-plus-sign"></i>
                </a>
            </p>
        </div>
    </form>
</div>
<script type="text/javascript">
    // manually bootstrap angular app, in case there are multiple angular apps on a page
    angular.bootstrap('#relationships-app', ['relationships']);
</script>

Finally the JS that controls this page's behavior:

Code Block
languagejs
titlerelationships.js (from the coreapps module)
// a new "module" just for this page that depends on various modules from uicommons
angular.module('relationships', ['relationshipTypeService', 'relationshipService', 'personService', 'uicommons.widget.select-person' ]).
 
    // this page has a single controller, which gets several dependencies injected 
    controller('PersonRelationshipsCtrl', ['$scope', 'RelationshipTypeService', 'RelationshipService', 'PersonService', '$modal',
    function($scope, RelationshipTypeService, RelationshipService, PersonService, $modal) {


       <div class="dialog-header">
     // the model for our view
       <%= ui.message("coreapps.relationships.add.header", "{{ addDialogOtherLabel }}") %>$scope.thisPersonUuid = null;
        $scope.relationshipTypes  </div>= [];
        <div$scope.relationships class="dialog-content">= [];
 
        // this is invoked  <div>
            by ng-init="init($patient.patient.uuid)" in the gsp page, which is how we communicate that specific bit of
   <label>     // bootstrapping data to our javascript app
        $scope.init <%= ui.message("coreapps.relationships.add.choose", "{{ addDialogOtherLabel }}") %>function(personUuid) {
            $scope.thisPersonUuid = personUuid;
    </label>        // these   calls (which use $resource under <select-person ng-model="otherPerson" exclude-person="${ patient.patient.uuid }" />
            </div>the hood) are asynchronous, so we need to use .then on the promise they return
            RelationshipService.getRelationships({ v: 'default', person: <div class="add-confirm-spacer">personUuid }).then(function(result) {
                <div ng-show="otherPerson" >$scope.relationships = result;
                });
   <h3>${ ui.message("coreapps.relationships.add.confirm") }</h3>        RelationshipTypeService.getRelationshipTypes({ v: 'default' }).then(function(result) {
        <p>{{ addDialogThisLabel }}: ${ ui.format(patient.patient) } ${ ui.message("coreapps.relationships.add.thisPatient") }</p>
     $scope.relationshipTypes = result;
            });
      <p>{{ addDialogOtherLabel }}:

{{ otherPerson.display }}</p>      // Helper method, since after saving a relationship, the response object </div>we get back from the OpenMRS REST resource does not
   </div>     // include a full rep of its relationshipType, <div>so this helper gets the full rep that we download on init
     <button class="confirm right" ng-disabled="!otherPerson" ng-click="doAddRelationship()">${ ui.message("uicommons.save") }</button> $scope.relType = function(relationship) {
            if (!relationship) {
 <button class="cancel" ng-click="cancelAddRelationship()">${ ui.message("uicommons.cancel") }</button>              return null;
       </div>     }
   </div>     </div>     <div ng-show="relationshipToDelete" class="dialog" id="delete-relationship-dialog">return _.findWhere($scope.relationshipTypes, { uuid: relationship.relationshipType.uuid });
        }
 
  <div class="dialog-header">${ ui.message("coreapps.relationships.delete.header") }</div>   $scope.relationshipsByType = function(relationshipType, whichSide) {
 <div class="dialog-content">          return _.filter($scope.relationships, function(item) <form>{
                ${if ui.message("coreappsitem.relationships.delete.title") }relationshipType.uuid != relationshipType.uuid) {
                <p>    return false;
               <label>{{ relType(relationshipToDelete).aIsToB }}</label>
                if (whichSide ==  {{ relationshipToDelete.personA.display }}
 'A' && item.personB.uuid == $scope.thisPersonUuid) {
              </p>      return true;
         <p>       } else if (whichSide == 'B' && item.personA.uuid == $scope.thisPersonUuid) {
   <label>{{ relType(relationshipToDelete).bIsToA }}</label>               return true;
    {{ relationshipToDelete.personB.display }}           }
     </p>       });
        }
<button 
class="confirm right" ng-click="doDeleteRelationship(relationshipToDelete)">${ ui.message("uicommons.delete") }</button>    // ----------
        // Add New <button class="cancel" ng-click="cancelDeleteRelationship(relationshipToDelete)">${ ui.message("uicommons.cancel") }</button>
            </form>
  Relationship Dialog (maybe this should be refactored to be its own controller and child scope)
        </div>
    </div>
    <form id="existing-relationships"> ----------

        <div ng-repeat="relType in relationshipTypes">$scope.addDialogMode = null;
        $scope.addDialogThisLabel = '';
  <p>      $scope.addDialogOtherLabel = '';
        <label>{{ relType.aIsToB }}</label>
$scope.otherPerson = null;


             <span ng-repeat="rel in relationshipsByType(relType, 'A')" class="relationship">
$scope.showAddDialog = function(relationshipType, whichSide) {
            $scope.otherPerson = null;
    {{ rel.personA.display }}      $scope.addDialogMode = {
            <a ng-click="showDeleteDialog(rel)">    relationshipType: relationshipType,
                whichSide: whichSide
   <i class="small icon-remove"></i>       };
             </a>
      $scope.addDialogOtherLabel = whichSide == 'A' ? relationshipType.aIsToB : relationshipType.bIsToA;
         </span>   $scope.addDialogThisLabel = whichSide == 'A' ? relationshipType.bIsToA : relationshipType.aIsToB;
      <span ng-show="relType.aIsToB == relType.bIsToA" ng-repeat="rel in relationshipsByType$(relType, 'B')" class="relationship">'#select-other-person').focus();
        }

        $scope.doAddRelationship = function() {{ rel.personB.display }}
            var relationship = {
         <a ng-click="showDeleteDialog(rel)">      relationshipType: $scope.addDialogMode.relationshipType.uuid,
                 <i class="small icon-remove"></i>
   personA: $scope.addDialogMode.whichSide == 'A' ? $scope.otherPerson.uuid : $scope.thisPersonUuid,
                </a>
      personB: $scope.addDialogMode.whichSide == 'A' ? $scope.thisPersonUuid : $scope.otherPerson.uuid
         </span>   };
            var <acreated ng-click="showAddDialog(relType, 'A')">= RelationshipService.createRelationship(relationship);
            $scope.relationships.push(created);
        <i class="small icon-plus-sign"></i>  $scope.otherPerson = null;
            </a>
 $scope.addDialogMode = null;
        }

</p>        $scope.cancelAddRelationship = function() {
 <p ng-hide="relType.aIsToB == relType.bIsToA">        $scope.otherPerson = null;
      <label>{{ relType.bIsToA }}</label>    $scope.addDialogMode = null;
        }
 
<span ng-repeat="rel in relationshipsByType(relType, 'B')" class="relationship">   // ----------
        // Delete Relationship Dialog (maybe this should be {{ rel.personB.display }}
     refactored to be its own controller and child scope)
        // ----------

   <a ng-click="showDeleteDialog(rel)">    $scope.relationshipToDelete = null;

        $scope.showDeleteDialog = function(relationship) {
     <i class="small icon-remove"></i>     $scope.relationshipToDelete = relationship;
        }

   </a>     $scope.doDeleteRelationship = function(relationship) {
        </span>    RelationshipService.deleteRelationship(relationship);
            <a ng-click="showAddDialog(relType, 'B')">
$scope.relationships = _.reject($scope.relationships, function(item) {
                return item.uuid  <i class="small icon-plus-sign"></i>== relationship.uuid;
            });
          </a>  $scope.relationshipToDelete = null;
        </p>}

       </div> $scope.cancelDeleteRelationship = function(relationship) {
</form> </div> <script type="text/javascript">     // manually bootstrap angular app, in case there are multiple angular apps on a page
$scope.relationshipToDelete = null;
        }
   angular.bootstrap('#relationships-app', ['relationships' }]);
</script> 

 

Step 3 - Use an Extension to link to your screen from the patient summary

...