Back to the basics. In most of the cases data is coming from Model layer, from ADF BC or EJB. When user is changing data on the screen, frameworks takes care and preserves temporary data. However, what about such screens where we have temporary fields, without any relation with the Model layer - transient data fields. What if there is no corresponding Model implementation, and still we need to store field data between requests - where should we store it? I believer, one of the best techniques is to use Page Definition variables, this is old approach back from ADF 10g times - but it still works very well. Main advantage - we are able to store transient temporary data between requests and there is no need to define session scope bean.
It happened to see scary things - developers are defining managed beans in Page Flow Scope, just because they want to make sure temporary UI values are preserved between requests :)
Download sample application - PageDefVariables.zip. This sample implements two input components - inputText and inputNumberSlider. Both components are enabled with autoSubmit, as well as value change listener is defined for both. Once value is changed for one of the components, we recalculate total sum of both fields and display as total:
Both input components exist only in UI, there is no Model layer representation - user types values, total is recalculated immediately. However, we still need to store entered values, otherwise once we select number slider - partial request will be invoked and value entered for income will be lost. ADF developer would try to store input value inside Backing Bean:
It would be wrong to store temporary value inside Backing Bean - this bean lifetime is as long as request, in other words - once we will enter second input value, first will be always lost. You may think to define Session or even Page Flow Scope bean - that would make it work, but why to waste server memory - only if you want to make your ADF applications slow.
We can use Page Definition variables to store temporary values, these values will be preserved between requests. Open Page Definition, associated with the page, expand executables and select to insert new variable:
Give a name and specify a type for new variable:
In my example, I will define all three variables in the same way - for each of the fields:
Once variables are defined, we are not done yet with Page Definition. For every defined variable we need to define corresponding attribute (will be accessed from the page). Insert new item under bindings - Attribute Value:
When creating new Attribute Value, make sure to select variables as Data Source and map related variable (defined one step above) name:
Once all done, we should have following picture - each variable is assigned with attribute value:
Go back to UI now, input component should have its value property mapped with attribute value (not with variable directly, because data will not be stored/retrieved) from Page Definition. For example: bindings.incomeVarAttr.inputValue:
Once again - UI component value you should map with attribute value, not with variable directly:
Finally, you may ask question - how to access attribute values defined in Page Definition programmatically? Easy - use ADFUtils wrapper class. There are two methods available for your convenience - getBoundAttributeValue("name") and setBoundAttributeValue("name", value):
Its how it looks on UI:
It happened to see scary things - developers are defining managed beans in Page Flow Scope, just because they want to make sure temporary UI values are preserved between requests :)
Download sample application - PageDefVariables.zip. This sample implements two input components - inputText and inputNumberSlider. Both components are enabled with autoSubmit, as well as value change listener is defined for both. Once value is changed for one of the components, we recalculate total sum of both fields and display as total:
Both input components exist only in UI, there is no Model layer representation - user types values, total is recalculated immediately. However, we still need to store entered values, otherwise once we select number slider - partial request will be invoked and value entered for income will be lost. ADF developer would try to store input value inside Backing Bean:
It would be wrong to store temporary value inside Backing Bean - this bean lifetime is as long as request, in other words - once we will enter second input value, first will be always lost. You may think to define Session or even Page Flow Scope bean - that would make it work, but why to waste server memory - only if you want to make your ADF applications slow.
We can use Page Definition variables to store temporary values, these values will be preserved between requests. Open Page Definition, associated with the page, expand executables and select to insert new variable:
Give a name and specify a type for new variable:
In my example, I will define all three variables in the same way - for each of the fields:
Once variables are defined, we are not done yet with Page Definition. For every defined variable we need to define corresponding attribute (will be accessed from the page). Insert new item under bindings - Attribute Value:
When creating new Attribute Value, make sure to select variables as Data Source and map related variable (defined one step above) name:
Once all done, we should have following picture - each variable is assigned with attribute value:
Go back to UI now, input component should have its value property mapped with attribute value (not with variable directly, because data will not be stored/retrieved) from Page Definition. For example: bindings.incomeVarAttr.inputValue:
Once again - UI component value you should map with attribute value, not with variable directly:
Finally, you may ask question - how to access attribute values defined in Page Definition programmatically? Easy - use ADFUtils wrapper class. There are two methods available for your convenience - getBoundAttributeValue("name") and setBoundAttributeValue("name", value):
Its how it looks on UI:
Good one ;)
ReplyDeleteSo the important here is that is a way that we can use to get better performance, using pagedef variable in place of backing bean attribute.
ReplyDeleteis great idea..
Yes... and other thing - much easier to manage temporary values.
ReplyDeleteAndrejus
This is a helpful post. How would temporary values be done differently for declarative components?
ReplyDeleteJust in the same way. In Page Definition for declarative component.
ReplyDeleteAndrejus
A very good explanation about Page Definition Variables to Store Temporary Page Values.
ReplyDeleteExplained how the data comes and how to store the temporary data using variables.
Thanks.
Sample Documents
Great entry! :)
ReplyDeleteHi Andrejus,
ReplyDeleteGreat post! never knew of this feature.
Could you explain why this method would be more performant than saving these values in say pageflowScope or ViewScope ?
Regards,
Uday
Main reason is that pageFlowScope and viewScope stays clean and we can easier track what temporary values we are using. Plus we are leveraging ADF Model layer to store our data, without relying on memory scope.
ReplyDeleteIdeally, in pageFlowScope we should store only TF input parameters, by design.
viewScope remains active, only while on current page. But when storing temp values in ADF Model, values will remain - same as other values coming from ADF Model.
Andrejus
Thanks a lot for your reply Andrejus!
ReplyDeletePlease share your comments on another doubt of mine. I was just wondering if this implementation for saving temporary variables is HA compliant i.e. failover safe. When we put values into memory scopes and the scope is dirtied, it gets serialized and the changes are propagated to other nodes of the cluster. If a node goes down, the state is automatically recovered. Passivation takes care of temp. attributes in the BC layer. But, what about these page definition variables, are they also taken care off somewhere ?
Regards,
Uday
Yes, it should be replicated across cluster together with ADF Model values.
ReplyDeleteAndrejus
I am trying to use PageDefinition variables, but getting some issues. Values are getting lost. I have also posted a question on OTN forum..
ReplyDeletehttps://forums.oracle.com/forums/thread.jspa?messageID=10846833#10846833
Please let me know your comments.
Thanks,
Rajdeep
I am trying to
ReplyDelete(1) read data as initial value from a table
(2) display the data for user to edit and
(3) store the edited data in ANOTHER table
How do I do this simple thing in ADF Mobile? Can you send me an example. I have a deadline but seem to no where. Please help!
If you are using shared data control scope do you know if the variable attribute binding will be shared when you navigate between task flows or within regions or will you lose the stored value?
ReplyDeleteI would assume it should work, you would need to access different page definition context. Page def variables are supposed to be used in the current page def anyway.
ReplyDeleteRegards,
Andrejus
Thanks, it's really helpful.
ReplyDeleteI think we can use page definition variable only instead of view scope not pageflow scope,
Regards
Habib
Hi,
ReplyDeletefirst of all thanks for the post and for all your teaching work! It helps a lot.
I'm developing on JDEV 11g release 1 and I'm facing with this problem: on my JSFF page I've defined two beans (one that has request scope, used to handle a valueChangeEvent, and one that has pageFlow scope, used for other controls).
Unfortunately, if I set temporary variables from the first (in the method that handle valueChangeEvent), when I get them from the second, they are null!
can you explain what could be wrong?
Thanks a lot.
Piero