Versions Compared

Key

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

...

Code Block
titlecontroller, first pass
/**
 * Controller for the PatientIdentifiers fragment.
 * Displays a table of PatientIdentifiers, and allow the user to add another (via a short popup form),
 * or delete one (with confirmation) as long as it isn't the last one.
 */
public class PatientIdentifiersFragmentController {
	
	/**
	 * Controller method when the fragment is included on a page
	 */
	public void controller(PageModel sharedPageModel, FragmentConfiguration config, FragmentModel model) {
		model.addAttribute("patient", FragmentUtil.getPatient(sharedPageModel, config));
	}

}

...

Code Block
titleview, first pass
<%
    def id = config.id ?: ui.randomId("patientIdentifiers")
%>

<div id="${ id }">
    ${ ui.includeFragment("widgets/table", [
            columns: [
                [ property: "identifierType", heading: ui.message("PatientIdentifier.type") ],
                [ property: "identifier", userEntered: true, heading: ui.message("PatientIdentifier.identifier") ],
                [ property: "location", heading: ui.message("PatientIdentifier.location") ]
             ],
            rows: patient.activeIdentifiers,
            ifNoRowsMessage: ui.message("general.none")
        ]) }
</div>

It would be easy to write the html for the table ourselves, and this would be fine for a quick first pass, but in later steps we're going to want some more sophisticated behavior that we can get for free from the standard OpenMRS "table" widget, so we use that instead. (TODO: the ifNoRowsMessage functionality isn't implemented yet - TRUNK-2173)

Note:

  • for localization, we always use the ui.message() function instead of hardcoding user-visible messages in our views.
  • for security, we always display user-entered data with appropriate escaping
    • in this case we use that's the userEntered setting on the table column, but if we were displaying data ourselves we'd use ui.escapeHtml() or ui.escapeJs()
  • for UI consistency, we should always display standard OpenMRS classes with the ui.format() function. (That's taken care of here by the table widget.)

...

Code Block
titleadd a fragment action for fetching patient's active identifiers
/**
 * Controller for the PatientIdentifiers fragment.
 * Displays a table of PatientIdentifiers, and allow the user to add another (via a short popup form),
 * or delete one (with confirmation) as long as it isn't the last one.
 */
public class PatientIdentifiersFragmentController {
	
	/**
	 * Controller method when the fragment is included on a page
	 */
	public void controller(PageModel sharedPageModel, FragmentConfiguration config, FragmentModel model) {
		model.addAttribute("patient", FragmentUtil.getPatient(sharedPageModel, config));
	}
	
	/**
	 * Fragment Action for fetching list of active patient identifiers
	 */
	public ObjectResult getActiveIdentifiers(UiUtils ui,
	                                         @RequestParam("patientId") Patient patient) {
		return ObjectResult.build(ui, patient.getActiveIdentifiers(),
			"patientIdentifierId", "identifierType", "identifier", "location");
	}
}

...

Code Block
titlerefresh function in the view
<%
    def id = config.id ?: ui.randomId("patientIdentifiers")
%>
<script>
    function refreshPatientIdentifierTable(divId, patientId) {
        jq('#' + divId + '_table > tbody').empty();
        jq.getJSON('${ ui.actionLink("getActiveIdentifiers", [returnFormat: "json"]) }', { patientId: patientId },
        function(data) {
            publish(divId + "_table.show-data", data);
        });
    }
</script>

<div id="${ id }">
    <a href="javascript:refreshPatientIdentifierTable('${ id }', ${ patient.patientId })">test the refresh</a>

    ${ ui.includeFragment("widgets/table", [
            id: id + "_table",
            columns: [
                [ property: "identifierType", heading: ui.message("PatientIdentifier.type") ],
                [ property: "identifier", userEntered: true, heading: ui.message("PatientIdentifier.identifier") ],
                [ property: "location", heading: ui.message("PatientIdentifier.location") ]
             ],
            rows: patient.activeIdentifiers,
            ifNoRowsMessage: ui.message("general.none")
        ]) }
</div>

...

Code Block
titleRefresh on certain messages
<%
    def id = config.id ?: ui.randomId("patientIdentifiers")
%>
<script>
    function refreshPatientIdentifierTable(divId, patientId) {
        jq('#' + divId + '_table > tbody').empty();
        jq.getJSON('${ ui.actionLink("getActiveIdentifiers", [returnFormat: "json"]) }', { patientId: patientId },
        function(data) {
            publish(divId + "_table.show-data", data);
        });
    }

        function refreshPatientIdentifiers${ id }(message, data) {
        if (data)
            publish("${ id }_table.show-data", data.activeIdentifiers);
        else
            refreshPatientIdentifierTable('${ id }', ${ patient.patientId });
    }
 

      subscribe('${ id }.refresh', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }.changed', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }/identifiers.changed', refreshPatientIdentifiers${ id });
</script>

<div id="${ id }">
    <a href="javascript:publish('${ id }.refresh')">div id refresh</a>
    <a href="javascript:patientChanged(${ patient.patientId })">patient changed</a>
    <a href="javascript:patientChanged(${ patient.patientId }, 'identifiers')">identifiers changed</a>

    ${ ui.includeFragment("widgets/table", [
            id: id + "_table",
            columns: [
                [ property: "identifierType", heading: ui.message("PatientIdentifier.type") ],
                [ property: "identifier", userEntered: true, heading: ui.message("PatientIdentifier.identifier") ],
                [ property: "location", heading: ui.message("PatientIdentifier.location") ]
             ],
            rows: patient.activeIdentifiers,
            ifNoRowsMessage: ui.message("general.none")
        ]) }
</div>

...

Code Block
titleAdd Identifier fragment action, first pass
	/**
	 * Fragment Action for adding a new identifier
	 */
	public FragmentActionResult addIdentifier(UiUtils ui,
	                                          @RequestParam("patientId") Patient patient,
	                                          @RequestParam("identifierType") PatientIdentifierType idType,
	                                          @RequestParam("identifier") String identifier,
	                                          @RequestParam("location") Location location) {
		patient.addIdentifier(new PatientIdentifier(identifier, idType, location));
		Context.getPatientService().savePatient(patient);
		return new SuccessResult(ui.message("patientIdentifier.added"));
	}

...

Code Block
titlefragment view, now with add button
<%
    def id = config.id ?: ui.randomId("patientIdentifiers")
%>
<script>
    function refreshPatientIdentifierTable(divId, patientId) {
        jq('#' + divId + '_table > tbody').empty();
        jq.getJSON('${ ui.actionLink("getActiveIdentifiers", [returnFormat: "json"]) }', { patientId: patientId },
        function(data) {
            publish(divId + "_table.show-data", data);
        });
    }


       function refreshPatientIdentifiers${ id }(message, data) {
        if (data)
            publish("${ id }_table.show-data", data.activeIdentifiers);
        else
            refreshPatientIdentifierTable('${ id }', ${ patient.patientId });
    }
 

      subscribe('${ id }.refresh', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }.changed', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }/identifiers.changed', refreshPatientIdentifiers${ id });
</script>

<div id="${ id }">
    ${ ui.includeFragment("widgets/table", [
            id: id + "_table",
            columns: [
                [ property: "identifierType", heading: ui.message("PatientIdentifier.identifierType") ],
                [ property: "identifier", userEntered: true, heading: ui.message("PatientIdentifier.identifier") ],
                [ property: "location", heading: ui.message("PatientIdentifier.location") ]
             ],
            rows: patient.activeIdentifiers,
            ifNoRowsMessage: ui.message("general.none")
        ]) }
   

    ${ ui.includeFragment("widgets/popupForm",
        [
            id: id + "_add",
            buttonLabel: ui.message("general.add"),
            popupTitle: ui.message("patientIdentifier.add"),
            fragment: "patientIdentifiers",
            action: "addIdentifier",
            submitLabel: ui.message("general.save"),
            cancelLabel: ui.message("general.cancel"),
            fields: [
                [ hiddenInputName: "patientId", value: patient.patientId ],
                [ label: ui.message("PatientIdentifier.identifierType"), formFieldName: "identifierType", class: org.openmrs.PatientIdentifierType ],
                [ label: ui.message("PatientIdentifier.identifier"), formFieldName: "identifier", class: java.lang.String ],
                [ label: ui.message("PatientIdentifier.location"), formFieldName: "location", class: org.openmrs.Location ]
            ]
        ]) }
</div>

...

Code Block
titleDelete Identifier fragment action, first pass
	/**
	 * Fragment Action for deleting an existing identifier
	 */
	public FragmentActionResult deleteIdentifier(UiUtils ui,
	                                             @RequestParam("patientIdentifierId") Integer id) {
		PatientService ps = Context.getPatientService();
		PatientIdentifier pid = ps.getPatientIdentifier(id);
		ps.voidPatientIdentifier(pid, "user interface");
		return new SuccessResult(ui.message("PatientIdentifier.deleted"));
	}

...

Code Block
titlefragment view, now with delete button
<%
    def id = config.id ?: ui.randomId("patientIdentifiers")
%>
<script>
    function refreshPatientIdentifierTable(divId, patientId) {
        jq('#' + divId + '_table > tbody').empty();
        jq.getJSON('${ ui.actionLink("getActiveIdentifiers", [returnFormat: "json"]) }', { patientId: patientId },
        function(data) {
            publish(divId + "_table.show-data", data);
        });
    }

        function refreshPatientIdentifiers${ id }(message, data) {
        if (data)
            publish("${ id }_table.show-data", data.activeIdentifiers);
        else
            refreshPatientIdentifierTable('${ id }', ${ patient.patientId });
    }

        subscribe('${ id }.refresh', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }.changed', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }/identifiers.changed', refreshPatientIdentifiers${ id });
   

    subscribe('${ id }_table.delete-button-clicked', function(message, data) {
        if (prettyConfirm('${ ui.message("general.confirm") }')) {
            jq.post('${ ui.actionLink("deleteIdentifier") }', { returnFormat: 'json', patientIdentifierId: data },
            function(data) {
                location.reload(true);
            })
            .error(function() {
                flashError("Programmer error: delete identifier failed");
            })
        }
    });
</script>

<div id="${ id }">
    ${ ui.includeFragment("widgets/table", [
            id: id + "_table",
            columns: [
                [ property: "identifierType", heading: ui.message("PatientIdentifier.identifierType") ],
                [ property: "identifier", userEntered: true, heading: ui.message("PatientIdentifier.identifier") ],
                [ property: "location", heading: ui.message("PatientIdentifier.location") ],
                [ actions: [
                    [ action: "event",
                        icon: "delete24.png",
                        tooltip: ui.message("PatientIdentifier.delete"),
                        event: "delete-button-clicked",
                        eventPrefix: id,
                        property: "patientIdentifierId" ]
                ] ]
            ],
            rows: patient.activeIdentifiers,
            ifNoRowsMessage: ui.message("general.none")
        ]) }


       ${ ui.includeFragment("widgets/popupForm",
        [
            id: id + "_add",
            buttonLabel: ui.message("general.add"),
            popupTitle: ui.message("PatientIdentifier.add"),
            fragment: "patientIdentifiers",
            action: "addIdentifier",
            submitLabel: ui.message("general.save"),
            cancelLabel: ui.message("general.cancel"),
            fields: [
                [ hiddenInputName: "patientId", value: patient.patientId ],
                [ label: ui.message("PatientIdentifier.identifierType"), formFieldName: "identifierType", class: org.openmrs.PatientIdentifierType ],
                [ label: ui.message("PatientIdentifier.identifier"), formFieldName: "identifier", class: java.lang.String ],
                [ label: ui.message("PatientIdentifier.location"), formFieldName: "location", class: org.openmrs.Location ]
            ]
        ]) }
</div>

...

Code Block
titleController, almost final
/**
 * Controller for the PatientIdentifiers fragment.
 * Displays a table of PatientIdentifiers, and allow the user to add another (via a short popup form),
 * or delete one (with confirmation) as long as it isn't the last one.
 */
public class PatientIdentifiersFragmentController {
	
	/**
	 * Controller method when the fragment is included on a page
	 */
	public void controller(PageModel sharedPageModel, FragmentConfiguration config, FragmentModel model) {
		model.addAttribute("patient", FragmentUtil.getPatient(sharedPageModel, config));
	}
	
	/**
	 * Fragment Action for fetching list of active patient identifiers
	 */
	public ObjectResult getActiveIdentifiers(UiUtils ui, @RequestParam("patientId") Patient patient) {
		return ObjectResult.build(ui, patient.getActiveIdentifiers(), "patientIdentifierId", "identifierType", "identifier",
		    "location");
	}
	
	/**
	 * Fragment Action for adding a new identifier
	 */
	public FragmentActionResult addIdentifier(UiUtils ui, @RequestParam("patientId") Patient patient,
	        @RequestParam("identifierType") PatientIdentifierType idType, @RequestParam("identifier") String identifier,
	        @RequestParam("location") Location location) {
		patient.addIdentifier(new PatientIdentifier(identifier, idType, location));
		Context.getPatientService().savePatient(patient);
		return FragmentUtil.standardPatientObject(ui, patient);
	}
	
	/**
	 * Fragment Action for deleting an existing identifier
	 */
	public FragmentActionResult deleteIdentifier(UiUtils ui, @RequestParam("patientIdentifierId") Integer id) {
		PatientService ps = Context.getPatientService();
		PatientIdentifier pid = ps.getPatientIdentifier(id);
		ps.voidPatientIdentifier(pid, "user interface");
		return FragmentUtil.standardPatientObject(ui, pid.getPatient());
	}
	
}

The only change we've made is to return a ObjectResult representing a standard patient, instead of a SuccessResult.

...

Code Block
titleView, final
<%
    def id = config.id ?: ui.randomId("patientIdentifiers")
%>
<script>
    function refreshPatientIdentifierTable(divId, patientId) {
        jq('#' + divId + '_table > tbody').empty();
        jq.getJSON('${ ui.actionLink("getActiveIdentifiers", [returnFormat: "json"]) }', { patientId: patientId },
        function(data) {
            publish(divId + "_table.show-data", data);
        });
    }
 

      function refreshPatientIdentifiers${ id }(message, data) {
        if (data)
            publish("${ id }_table.show-data", data.activeIdentifiers);
        else
            refreshPatientIdentifierTable('${ id }', ${ patient.patientId });
    }
  

     subscribe('${ id }.refresh', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }.changed', refreshPatientIdentifiers${ id });
    subscribe('patient/${ patient.patientId }/identifiers.changed', refreshPatientIdentifiers${ id });
   

    subscribe('${ id }_table.delete-button-clicked', function(message, data) {
        if (openmrsConfirm('${ ui.message("general.confirm") }')) {
            jq.post('${ ui.actionLink("deleteIdentifier") }', { returnFormat: 'json', patientIdentifierId: data },
            function(data) {
                flashSuccess('${ ui.escapeJs(ui.message("PatientIdentifier.deleted")) }');
                publish('patient/${ patient.patientId }/identifiers.changed', data);
            }, 'json')
            .error(function() {
                flashError("Programmer error: delete identifier failed");
            })
        }
    });
</script>

<div id="${ id }">
    ${ ui.includeFragment("widgets/table", [
            id: id + "_table",
            columns: [
                [ property: "identifierType", heading: ui.message("PatientIdentifier.identifierType") ],
                [ property: "identifier", userEntered: true, heading: ui.message("PatientIdentifier.identifier") ],
                [ property: "location", heading: ui.message("PatientIdentifier.location") ],
                [ actions: [
                    [ action: "event",
                        icon: "delete24.png",
                        tooltip: ui.message("PatientIdentifier.delete"),
                        event: "delete-button-clicked",
                        eventPrefix: id,
                        property: "patientIdentifierId" ]
                ] ]
            ],
            rows: patient.activeIdentifiers,
            ifNoRowsMessage: ui.message("general.none")
        ]) }
   

    ${ ui.includeFragment("widgets/popupForm", [
            id: id + "_add",
            buttonLabel: ui.message("general.add"),
            popupTitle: ui.message("PatientIdentifier.add"),
            fragment: "patientIdentifiers",
            action: "addIdentifier",
            submitLabel: ui.message("general.save"),
            cancelLabel: ui.message("general.cancel"),
            fields: [
                [ hiddenInputName: "patientId", value: patient.patientId ],
                [ label: ui.message("PatientIdentifier.identifierType"), formFieldName: "identifierType", class: org.openmrs.PatientIdentifierType ],
                [ label: ui.message("PatientIdentifier.identifier"), formFieldName: "identifier", class: java.lang.String ],
                [ label: ui.message("PatientIdentifier.location"), formFieldName: "location", class: org.openmrs.Location ]
            ],
            successEvent: "patient/" + patient.patientId + "/identifiers.changed"
        ]) }
</div>

...