Text tree to Tree component 'items' property

I'm experimenting with using the Tree component for navigation rather than the Menu Tree. It offers the user clear visibility of where in the site they are whereas the Menu Tree doesn't.

I'm making the tree configurable within the application (subject to user roles) and want to use a simple markup structure to generate the Tree's props.items.

Markup would look like this with the syntax anchor text | page URL. The URL can be passed to the tree's onActionPerformed event to cause a navigation to the URL specified in props.selection.0.value.url.

A001            |/Home
A001/B001       |/Area/1/Bath/1
A001/B001/C001  |/Area/1/Bath/1/Clamp1
A001/B001/C002  |/Area/1/Bath/1/Clamp2
A001/B001/C003  |/Area/1/Bath/1/Clamp3
A002            |/Area/2
A002/B001       |/Area/2/Bath/1
A002/B002       |/Area/2/Bath/2
A003            |/Area/3
A003/B001       |/Area/3/Bath/1
A003/B001/C001  |/Area/3/Bath/1/Clamp1
A003/B001/C002  |/Area/3/Bath/1/Clamp1
A003/B001/C003  |/Area/3/Bath/1/Clamp1

I would appreciate some help in generating the items list for the tree.

Each item is a dictionary of form,

{
    "label": "Anchor text goes here.",
    "expanded": false,
    "data": {
        "url": "Page URL goes here."
    },
    "items": []
}

Could anyone give me a starter on a recursive procedure to generate the items based on the markup and dictionary template?

Many thanks.

I've been using a modified version of this:

I'm using this code in a script transform. Original binding is to a dataset containing path data. ex: "A/B/C"

items = []
for row in range(value.rowCount):
	path = value.getValueAt(row, 0)
	
	current = items
	for part in path.split("/"):

		# Check if the current folder exists in our items list
		folderExists = False
		for itemsPointerItem in current:
			if part == itemsPointerItem['label']:
				folderExists = True
				current = itemsPointerItem['items']

		if not folderExists:
			item = {
				"label": part,
				"expanded": False,
				"items": [],
				"data": path,
				"icon": {
				  	'path': 'material/stop',
				  	'color': 'red',
				  	'style': {}
				} 
			}
			current.append(item)
			current = item['items']

return items
1 Like

Thank you for that. I've got your code working. If anyone wants to try it out then past the code below into an expression binding on a Tree component's props.items.

Tree component test binding code.
	# Temporary test string.
	value ='''A001
	A001/B001
	A001/B001/C001
	A001/B001/C002
	A001/B001/C003
	A002
	A002/B001
	A002/B002
	A003
	A003/B001
	A003/B001/C001
	A003/B001/C002
	A003/B001/C003'''
	
	
	items = []
	for path in value.splitlines():
		current = items
		for part in path.split("/"):
	
			# Check if the current folder exists in our items list
			folderExists = False
			for itemsPointerItem in current:
				if part == itemsPointerItem['label']:
					folderExists = True
					current = itemsPointerItem['items']
	
			if not folderExists:
				item = {
					"label": part,
					"expanded": False,
					"items": [],
					"data": path
				}
				current.append(item)
				current = item['items']
	
	return items

Tree generator
The result.

Now to work on my navigation tree ...

Success!

  • Create a source of the menu structure in text.
  • Create an Expression Binding on the Tree's props.items to your text.
  • Add a script transform on the expression binding and paste in the following code.
#	Anchors and path URLs to be provided in form shown below using '|' (vertical bar) as separator.
#	A001            |/Home
#	A001/B001       |/Area/1/Bath/1
#	A001/B001/C001  |/Area/1/Bath/1/Clamp1	
	items = []
	
	for path in value.splitlines():
		if path.strip():						# Check for empty lines.
			current = items
			branch, url = path.split('|')

			for part in branch.strip().split("/"):		# Strip off leading and trailing spaces.
				folderExists = False					# Check if the current folder exists in our items list.
				for itemsPointerItem in current:
					if part == itemsPointerItem['label']:
						folderExists = True
						current = itemsPointerItem['items']
		
				if not folderExists:
					item = {
						"label": part,
						"expanded": False,
						"items": [],
						"data": {"url": url.strip()}
					}
					current.append(item)
					current = item['items']
	
	return items

The result is the same as my post above.

@Matthew.gaitan, thank you for the link. It saved me many hours, I suspect. I've edited the original question to better match the solution and remove some of my woolly thinking. I've marked this answer as the "solution" as it provides the full answer to my question, but thank you very much for your help.

1 Like