...
The view for this page is large, and will require some AngularJS knowledge to understand (TO DO describe this better):
Code Block | ||||
---|---|---|---|---|
| ||||
<% // 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 | ||||
---|---|---|---|---|
| ||||
// 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
...