Maintaining APEX Tree Region Expansion State

Doug Gault APEX 2 Comments

As soon as I was finished with the first incarnation of the ORDS REST Workshop for release in APEX 18.1, I had a list as long as my arm of things that I wanted to do to improve it. Some small, some large.

One of the things that bugs me the most is that the APEX Tree region on the left side of the page doesn’t, by default, remember its expansion state. Originally that meant that every time you clicked a node and navigated to a new page, it would fully collapse on itself.  Thinking that I would have time to come back and fix it later, I implemented a quick fix to make the tree fully expand every time. The problem was that, while working on the other, more esoteric functionality, I let too much time slip by and I wan’t able to go back and implement a proper solution before it was time for UI freeze.

If you’re working with a relatively small number of RESTful services, this doesn’t pose too much of a problem. However, if you’re working with more than just a few, having the tree fully expended with every page refresh very quickly starts to get annoying.

So, for APEX 19.1 one of my first priorities was to fix this. Little did I know how simple the fix really was.

Documentation to the Rescue

One of the things that has improved in the more recent versions of APEX has been the JavaScript API documentation. Included therein is documentation on the treeVeiw object used by the APEX Tree Region.

A quick peruse of the methods shows that there are a a number of ways we could approach the problem but after a little reading I landed on the technique outlined below.

I’m sure there are other ways to do this and probably at least 50% of them will be better than my way, but it works and its simple. Two criteria I try to let guide my coding!

A Tree, Two Dynamic Actions and a Cookie

Creating the tree is the easy part. In my example I used a simple tree over the EMP table. Just for fun I hooked it up to a classic report that shows the direct reports of the person selected in the tree. Single-clicking on a tree node would navigate back to the same page, passing the EMPNO of the user you selected so that it could be used in the report.

For maintaining the Tree’s sate, the first problem to attack was that of getting and saving the trees expanded state so that it can be reinstated when you come back to the page.

For this I chose to use the getExpandedNodeIds method. This method returns an array of node ids from the associated data model for each expanded node.
Because I wanted to save the tree state, regardless of what caused the navigation, I chose to create a Dynamic Action triggered on Page Unload.

The True action of the Dynamic Action would be to execute the following JavaScript:

// Get a handle on the tree using regionStaticID_tree. Then use the treeView to get the expanded Nodes
var exp$ = $("#empTree_tree").treeView("getExpandedNodeIds");
// Create a cookie and store the nodes that are expanded
// The toString will change the array into a comma separated string.
apex.storage.setCookie('myTreeState', exp$.toString());
  • Line 2 gets the selected nodes and stores them in the array named exp$
  • Line 6 uses the apex.storage.setCookie javascript function to store the selected nodes in the users’s browser. the exp$.toString() function basically takes the array and creates a comma separated string that is easy to store

When navigating away from the page for any reason, the values of the selected nodes are now stored in a browser cookie called myTreeState.

Now all we need to do is restore that state when we’re going the other direction. For this we’ll use another Dynamic Action triggered On Page Load.

The True action of the Dynamic Action would be to execute the following JavaScript:

 

// Get a handle on the tree using regionStaticID_tree
var tree$ = $("#empTree_tree");
// Get the value of the cookie named myTreeState
var myTreeState = apex.storage.getCookie("myTreeState");
// If the Cookie is not null then loop through and expand the tree
if (myTreeState) 
{
	// Split the value of the cookie and make an array
	var $expNodes = myTreeState.split(",");
	// Loop Through the array and for each entry
	$expNodes.forEach(function (id) {
		// Identify the Tree Nodes that relate to the saved values
		var node$ = tree$.treeView("find",{ 
			depth : -1, 
			findAll: false, 
			match: function(node){ 
				return node.id == id
			}
	}) 
	// Expand those nodes.
	tree$.treeView("expand", node$)
	}) 
}
  • Line 2 gets a handle on the tree itself and assigns it to tree$
  • Line 4 uses apex.storage.getCookie to retrieve any values from the user’s browser into the variable myTreeState
  • Line 6 checks to see if there were any values to retrieve. If there weren’t then there is no need to reinstate them.
  • Line 9 splits the string that was stored and creates an array of node ids called $expNodes
  • Line 11 loops through each item in the array
  • Lines 13 through 19 identify the tree nodes that match the values we saved and creates an array of node$
  • Line 21 accesses the treeView of tree$ and expands the nodes held in the array.

The end result is that the tree will be set back to its previous state after having navigated away and then back.

I hope that someone finds this useful and that it shows just how simple it can be to interact with the APEX JavaScript APIs now that there is good documentation.

Comments 2

  1. hi, thanks very much that save me, followed and applied changes as per given example.
    I am facing a problem, actually came with Oracle Forms background, we have LOV with Multiple Items Return from and it exists since ver. 6 (as per my experience), when trying to have in Oracle Apex, it lacks of this feature even in 19.1, some people are saying it can achieve using Modal with IR to return multiple values at once, i tries some examples but still failed to have a working LOV, at our client, we have to migrate from Forms 10g to Apex but their various transactions Forms contains LOV with at least 2 column returns, say Customer ID and Account ID, how I can achieve this, can you or somewhere else has guide step-by-step ( I don’t know much about use of JS and also not have much knowledge of Apex ), so I can successfully achieve it? is there any link for the solution?
    regards

    1. Post
      Author

      Hello Ahmed,

      You’re correct that returning multiple values from a single LOV is not a native feature in APEX 19.1. However, we’re currently working on a new feature (targeted for APEX 19.2) that will allow you to do exactly that, natively!

      I know that doesn’t help you right now, so in the mean time have a look at SkillBuilders Super LOV. I believe this will give you the functionality you’re looking for.

      Hope this helps…

      Doug

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.