How to query patient gender to conditionally enable a concept?

What is the syntax to query patient gender in formConditions.js in order to conditionally enable a concept in an Observation form. e.g., display Ob/gyn history only if patient.gender == ‘F’ ?

https://bahmni.atlassian.net/wiki/display/BAH/Create+a+New+Observation+Form#CreateaNewObservationForm-Conditionallyenable/disableConcepts

1 Like

@dsurrao

The Gender attribute on the registration page is “mrs.genders”(In OpenMRS admin --> Administartion–> Advanced Settings, you will find this property), its a default mandatory person attribute provided by OpenMRS. I don’t think this person attribute value can be referred to an Observation form level. It might be worth testing.

Incase you have Gender defined as a concept in the dictionary then you can use that concept on the corresponding Obs form and there should be no difficulty in referring that value in formCondition.js

As @vmalini mentioned, form conditions are used in the context of observations. so, there isn’t any hook to query on the patient attributes. However, I understand the use case of conditionally enabling or disabling the forms based on the gender attribute. What can be done ? openms-modules-bahmniapps should also pass the patient object (which contains person attributes also) to formsConditions.js and then patient object can be used in formcondition.js to enable/disable the observations. For example: > ‘Systolic Data’ : function (formName, formFieldValues, patient) { > if (patient[‘gender’] == ‘Female’) { > return { > enable: [“Posture”] > } > } else { > return { > disable: [“Posture”], > error: “Error message here if any” > } > } > }

1 Like

Hello @sravanthi17 please help me understand you said openmrs-modules-bahmniapps should pass patient object , how can i achieve this?

I am very interested in this feature too. I need to display some of the observations conditionally based on patient’s age or gender.

openmrs-module-bahmniapps is the repo where UI code stays. right now, conceptSet.js uses form name and the field values to evaluate the condition configured via formConditions.js This method has to be enhanced to also pass the patient related information, so that the formConditons can refer to patient related fields like person attributes(gender, age etc). If you are interested, please make these necessary changes and raise a pull request to Bahmni.

This is where the modification could happen:

Just call to the formCondition() method with the ‘patient’ argument:

var conditions = formCondition(formName, valueMap, $scope.patient);

Here is the PR:


Then this can be used in the formConditions.js as mentionned by @sravanthi17

'Systolic Data' : function (formName, formFieldValues, patient) {
    var patientGender = patient['gender'];
    var patientAge = patient['age'];

    if (patientGender == 'M' || patientAge > 10 ) {
        return {
            enable: ["Posture"]
        }
    } else {
        return {
            disable: ["Posture"]
        }
    }
},
1 Like

thank you @mksrom and @sravanthi17, this will be very helpful!

Thanks @mksrom. Some one from the team will review and merge the pull request.

Do we want to pass the entire patient object to the function? Will this leak states to places where we might not want?

I would rather have it minimalistic to begin with. for example, expose patientContext (a wrapper object) as a function parameter, with read-only functions like - getDob(), getGender(), etc.

note. during our design discussions in new form engine (using reactjs), this has come up multiple times and one of the thoughts we had was that, we would rather not pass the patient object directly reference-able, because someone might change or modify info that might cause unintended effects (for which we would prefer specific operation call instead)

something like > var patientContext = { “getGender” : function() { return $scope.patient.gender; }, “getAge” : function() { return $scope.patient.age; } }; > var conditions = formCondition(formName, valueMap, patientContext);

or more fancy

var patientInfo = $scope.patient;
var patientContext = {"getValue" : function(attribute) { 
	 var context = patientInfo;	
	 var value = null;
	 var attribs = attribute.split(".");
	 for(var i=0; i < attribs.length; i++) {
   		value = context[attribs[i]];
   		context = value;
	 }
	 return value;
}}; 

This would allow us to get info > patientContext.getValue(“age”) > patientContext.getValue(“address.village” )

or Maybe the above function is not the way to go. I would suggest that we progressively allow for such contextual getters from patient. so we can start with age, gender … identifiers etc. then opening up (as demanded) to more patientContext.getAddress() or patientContext.getRelations() or patientContext.getCurrentVisitDetails()

Thoughts?

OK. Yes, that totally makes sense to not pass the ‘real’ patient object by reference.

I personally prefer to access objects properties as fields of the object (or as getters) rather than fetching them by name as a string (getValue("age")). I find it less error-prone and think that it makes debugging easier as well as better documented for the developers; one can more easily find what fields are available to use on this patientContext object. So I would vote for the first solution you mentioned:

The drawback is obviously that if someone needs a new field, this needs to be implemented and PRed. But still I would go for the getters…

As I mentioned on slack, my preference is that the patient context functions like a read-only plain json object, and that we use exactly the REST representation for this object.

I understand the desire not to bloat the context with imagined needs, but…

+10 to this being really annoying. We took this approach in the HTML Form Entry module and I regret the time spent manually adding another dumb getter function, releasing a new version, and getting it deployed to the field, just to let someone use a value we could have given them in the context in the first place.

There’s definitely value in mutating context/state happening in a controlled way, but we’re not talking about doing that here.

So, personally I’m fine with just exposing a read-only object that’s plain JSON. I can live with forcing people to access its values via a generic getter, like patientContext.get("address.village"), but I really think it’s a mistake to have write a bunch boilerplate of Java-style property accessors like patientContext.getAddress().village or patientContext.getAddress().getVillage().

1 Like

I think its more about state changes that we want to allow and from where. IMO, in a reactive/observable environment that we run on (angularjs models and components, react/redux etc), its better to be restrictive in terms of which component can do state changes and how.

The patient object is reference-able from all across the consultation app. More references, accessors, more watchers, more mutations, more side effects. The amount of time we have spent on debugging leaking memory is not “small”.

I would forego ease of development for unforeseen accessors than unwanted side effects. In all these years of existence of Bahmni, we have come across requests for only age, gender accessors.

Guys, we need some resolution to the above. I am not a fan of exposing information where it is not needed and allowing mutations even if accidentally.

  • I don’t know how we can pass ‘readonly’ patient object to the function across browsers! Unless we override the property setters. and I am not sure if I have seen a all-browser compatible solution for hiding/overriding javascript object property accessors.

I suggest we just pass a new object

  • 2 functions - “getAge()” and “getGender()” - this will serve of the requirements that we know of and for people who like specific functions for attribute accessors.
  • A generic function like “getProperty(name)” or “get(propertyName)” - like the example I mentioned above, which will serve as a getter for other unforeseen attributes.

what do you all say?

I didn’t think we’d need to enforce read-only, just that we’d document that you’re not allowed to mutate or else bad things will happen. But if you want to ensure no mutation by using getter functions, that’s fine.

I propose that we only add:

  • get(propertyName) or getProperty(propertyName), whichever name makes more sense for the object we’re defining it on.
  • this supports getting simple properties that have fixed values
  • we can initially support just gender if you want to keep things limited
  • getAge()
  • this gets its own function because age is (a) calculated, and (b) may be approximate, so the return value should be more complex than just an integer
  • We might copy something from what the OpenMRS reporting module does here.

As to the property names for static properties that we expose, I suggest that we expose the same values that are otherwise accessible/documented in a REST representation of patient. In vanilla OpenMRS, the patient JSON object you get from REST looks like this:

{
    "identifiers": [ ... ],
    "person": {
        "birthdate": ...,
        "gender": ...,
        ...
    }
}

I would lean towards adopting this same structure for consistency. (E.g. you’d have to call get("person.gender").

Or do we have a standard JSON representation of a patient in Bahmni that would be more appropriate to use than this?