How to conditionally display forms

Hi everyone,

I’d like to display a form only on specific condition (for instance, when the VisitType is “Emergency”).

I see that there is a Show If field in the form metadata screen:

What can I write in this field, which language ? Is there any example ?

Thank you

Romain

This should be a javascript expression that will be evaluated against “appContextModel” as built here:

At present the VisitContextModel class it uses (see

) does not include the VisitType, but you are pre-approved to add it to that class (ideally in a way that is consistent with what the JSON REST representation of a visit’s visit type would be, e.g. as an object with uuid and name properties).

Thanks for the prompt answer.


One question when you say:

add it to that class (ideally in a way that is consistent with what the JSON REST representation of a visit’s visit type would be, e.g. as an object with uuid and name properties).

If I do something like:

...
private VisitType visitType;

	public VisitContextModel(VisitDomainWrapper visit) {
		...
		this.visitType = visit.getVisit().getVisitType();
		...
	}

That’ll add the VisitType object to the ContextModel.

Then I guess in the Javascript:

  • appContextModel.visit.visitType.uuid
  • appContextModel.visit.visitType.name
  • appContextModel.visit.visitType.id
  • … and all fields

will be automatically available right ?

Or should I specify somewhere which field of VisitType object I want to add in the VisitContextModel ?

What you’re describing would be the least code, but there’s one thing…

The philosophy is that we want these same extension points to be usable in a server-side Java-rendered page, or in a client-side JS-rendered page. So the philosophy is that we do not want to use the Java domain objects as the context model, but rather in the long run we want to use the JSON REST representation of the visit, rather than the visit. You can see from looking at VisitContextModel that we haven’t actually done things this way yet, because nobody has taken the time to go back and refactor everything that was depending on the current representation.

So, as far as what you should do, one thing would be instead of this:

private VisitType visitType;
...
this.visitType = visit.getVisit().getVisitType();

to instead do this:

private SimpleObject visitType;
...
this.visitType = ConversionUtil.convertToRepresentation(visit.getVisit().getVisitType(), Representation.DEFAULT); // these are from the webservices.rest module

The code will look a bit out of place at this point in time, but it’s going in the direction we want to go. Does that make sense?

Also, the javascript fragment doesn’t need to say “appContextModel”, as in this example here: https://github.com/openmrs/openmrs-module-referenceapplication/blob/master/omod/src/main/resources/apps/visitActions_extension.json#L23

Thanks for this detailed explanation. That’s very clear indeed.

I’ll create a ticket for that task

Ticket now created

I am working on the ticket now. @darius and @mksrom thanks for making it so clear.

2 Likes

@mksrom Kindly let us know when you are done working on this ticket. Am also looking using this option.

Hi @jmpango, Sure thing. Will let you know soon.

Thanks.

@darius Does the app context model also extend to Encounters? I would like to disable some forms if a specific encounter has not happened yet.

I don’t think it’s currently there. I would be wary of bloating the visit context model, but I guess having a list of encounter type that have happened already in the visit might be worthwhile.

Can you give some real examples?

-Darius (by phone)

@darius In Uganda we have an initiation encounter for ART used to collect baseline information for treatment. Once this happens then a patient will have other encounters for counseling and regular visits (monthly - to pick up drugs and get a checkup).

Limiting forms for counseling and other visits not to display until the initiation encounter has happened will reduce the incidences of missing data.

@darius
@ssmusoke @mksrom

i get this error from travis after pushing changes to my repo.

http://pastebin.com/r15PZDcU

and the detailed travis log is https://travis-ci.org/openmrs/openmrs-module-coreapps/builds/194749572

I have looked at the problems and they are

1:Could not find Symbol SimpleObject 2:Could not find Symbol ConversionUtil

was wondering how to get ConversionUtil into VisitTypeContextModel from webservices.rest module… Any way i can rectify this

@tendomart The SimpleObject class is not imported in the VisitContextModel class. Did you run an mvn clean install before pushing your commit?

Why are you using the SimpleObject and not a String for the name of the visit type?

@ssmusoke no i did not run mvn clean install,the directions or atleast the hint given earlier in this post seem to point in that direction.I had earlier used visit type but refactored because of what i read from this thread… Consider what darius said earlier in this post here is the link to github https://github.com/openmrs/openmrs-module-coreapps/pull/51

i refactored as at http://pastebin.com/kzpfF4c0

and running a mvn clean install before committing throws this http://pastebin.com/QgYKBDgB

i read through the lines but am stuck on what to do…a little help here

@tendomart your class does not import the external classes referred to. I do think that the visitType has to be a String - but I am not an expert on the context models.

@ssmusoke thanks i appreciate,that insight

Hi I did start working on this. I think that onversionUtil.convertToRepresentation() is in the artifact webservices.rest-omod-common.

However adding it as a dependency to coreapps pom causes my mvn tests to fail:

Running org.openmrs.module.coreapps.htmlformentry.EncounterDispositionTagHandlerComponentTest
ERROR - TestContextManager.prepareTestInstance(309) |2017-03-26 14:30:33,571| Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@33b92d63] to prepare test instance [org.openmrs.module.coreapps.htmlformentry.EncounterDispositionTagHandlerComponentTest@69339b3b]
java.lang.IllegalStateException: Failed to load ApplicationContext
	at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
	at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:307)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainResourceController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.openmrs.module.webservices.rest.web.api.RestService org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceController.restService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.openmrs.module.webservices.rest.web.api.RestService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1146)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
	at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
	at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
	at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
	... 26 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.openmrs.module.webservices.rest.web.api.RestService org.openmrs.module.webservices.rest.web.v1_0.controller.MainResourceController.restService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.openmrs.module.webservices.rest.web.api.RestService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:517)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
	... 42 more

I add these in the parent pom:

<properties>
    <webservicesRestVersion>2.8</webservicesRestVersion>
</properties>

<dependencyManagement>
  <dependency>
		<groupId>org.openmrs.module</groupId>
		<artifactId>webservices.rest-omod-common</artifactId>
		<version>${webservicesRestVersion}</version>
		<scope>provided</scope>
</dependency>
</dependencyManagement>

and in coreapps/api/pom.xml:

<dependency>
         <groupId>org.openmrs.module</groupId>
          <artifactId>webservices.rest-omod-common</artifactId>
</dependency>

Any insights on what I’m doing wrong?

I see two SimpleObject classes, org.openmrs.module.webservices.rest.SimpleObject and org.openmr.ui.framework.SimpleObject

And the one from the rest module does not include any constructors that accepts other object types, but one in the UI module does have a constructor that accepts OpenmrsMetadata for constructing a SimpleObject.

And visitType also implements OpenmrsMetada

So can’t we use:

this.visitType = new org.openmrs.ui.framework.SimpleObject(visitType);

instead of using ConversionUtil from the rest module. BTW rest.webservices module is not included as a dependency in the coreapps module.

PR: https://github.com/openmrs/openmrs-module-coreapps/pull/80