# Dynamic accordion perspective

**URL:** <https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [February 25, 2024, 5:19am UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317 "2024-02-25T05:19:53Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Steven\_Cheron](https://avatars.discourse-cdn.com/v4/letter/s/ebca7d/32.png) [@Steven\_Cheron](https://forum.inductiveautomation.com/u/Steven_Cheron)\
**Post date:** [February 25, 2024, 5:19am UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/1 "2024-02-25T05:19:53Z")

</div>

Hello,

I have a table "Categories" in a database, I would like each category to create a new section in the accordion. But it doesn't works.

I have tried to copy the structure of one section in custom, and then duplicate it with a script. But it duplicate a reference to the copy, not the copy itself, and when I change the parameter to my view the initial copy was changed too.

Thanks,  
Steven Cheron

---

<div class="post-metadata">

**Author:** ![cmallonee](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmallonee/32/6416_2.png) [@cmallonee](https://forum.inductiveautomation.com/u/cmallonee)\
**Post date:** [February 25, 2024, 7:13am UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/2 "2024-02-25T07:13:04Z")

</div>

Bind Accordion.props.items against a Named Query which returns the categories as a list/set/array, and make sure to set the format of the binding to "json".  
Now add this transform.

```auto
def transform(self, value, quality, timestamp):
	return [{
				"expanded": False,
				"header": {
					"toggle": {
						"enabled": True,
						"expandedIcon": {
							"path": "material/expand_less",
							"color": "",
							"style": {
								"classes": ""
							}
						},
						"collapsedIcon": {
							"path": "material/expand_more",
							"color": "",
							"style": {
								"classes": ""
							}
						}
					},
				"content": {
					"type": "text",
					"text": category,
					"useDefaultViewWidth": False,
					"useDefaultViewHeight": False,
					"viewPath": "",
					"viewParams": {},
					"style": {
						"classes": ""
					}
				},
				"height": "40px",
				"reverse": False,
				"style": {
					"classes": ""
				}
			},
			"body": {
				"viewPath": "",
				"viewParams": {},
				"useDefaultViewWidth": False,
				"useDefaultViewHeight": False,
				"height": "auto",
				"style": {
					"classes": "",
					"margin": "16px"
				}
			}
		} for category in value]

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 25, 2024, 3:20pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/3 "2024-02-25T15:20:15Z")

</div>

> [@Steven\_Cheron](#):
>
> it duplicate a reference to the copy

FWIW, this is expected behavior of Python/Jython when manipulating objects. If you wish to use such a "template" pattern in your code, whether for Perspective or elsewhere, your instances need to be **deep copies** of the template before they are updated with the per-instance customizations.

---

<div class="post-metadata">

**Author:** ![Steven\_Cheron](https://avatars.discourse-cdn.com/v4/letter/s/ebca7d/32.png) [@Steven\_Cheron](https://forum.inductiveautomation.com/u/Steven_Cheron)\
**Post date:** [February 25, 2024, 3:27pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/4 "2024-02-25T15:27:27Z")

</div>

I was hoping there is other solutions than that. If the structure changed in the future my binding will be broken.

Maybe perspective can have a function to create the default structure like "system.perspective.createDefault(property)".

I haven't tried this already, but it will works.  
Thank you

---

<div class="post-metadata">

**Author:** ![Steven\_Cheron](https://avatars.discourse-cdn.com/v4/letter/s/ebca7d/32.png) [@Steven\_Cheron](https://forum.inductiveautomation.com/u/Steven_Cheron)\
**Post date:** [February 25, 2024, 3:29pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/5 "2024-02-25T15:29:28Z")

</div>

I've try with "copy.deepcopy()" but an exception is raised. I don't know which one, because the text was too long for the tooltip in the binding configurator. And there is no log in the gateway.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 25, 2024, 3:33pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/6 "2024-02-25T15:33:14Z")

</div>

Then hand-roll your own deep copy. And/or catch the exception to log it yourself.

---

<div class="post-metadata">

**Author:** ![Steven\_Cheron](https://avatars.discourse-cdn.com/v4/letter/s/ebca7d/32.png) [@Steven\_Cheron](https://forum.inductiveautomation.com/u/Steven_Cheron)\
**Post date:** [February 25, 2024, 5:33pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/7 "2024-02-25T17:33:27Z")

</div>

I got this exception

```auto
com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper$ObjectWrapper(): expected 40 args; got 0

```

This is the transform on my request

```auto
def transform(self, value, quality, timestamp):
	import copy
	logger = system.util.getLogger("RecipeList")
	
	items = []
	
	try:
		for c in value:
			item = copy.deepcopy(self.custom.defaultItem)
				
			item.header.content.viewParams.categoryId = c["id"]
			item.body.viewParams.categoryId = c["id"]
			
			items.append(item)
	except Exception as e:
		logger.info(str(e))
	
	return items

```

The copy of the default structure is `self.custom.defaultItem`

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 25, 2024, 5:36pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/8 "2024-02-25T17:36:11Z")

</div>

Looks like Perspective properties don't cooperate with jython's deepcopy(). Sorry. You'll have to roll your own.

---

<div class="post-metadata">

**Author:** ![Steven\_Cheron](https://avatars.discourse-cdn.com/v4/letter/s/ebca7d/32.png) [@Steven\_Cheron](https://forum.inductiveautomation.com/u/Steven_Cheron)\
**Post date:** [February 25, 2024, 5:57pm UTC](https://forum.inductiveautomation.com/t/dynamic-accordion-perspective/86317/9 "2024-02-25T17:57:23Z")

</div>

I found a solution, not sexy, but it's work easy 😀

```auto
def transform(self, value, quality, timestamp):
	items = []
	
	for i, c in enumerate(value):
		item = system.util.jsonDecode(system.util.jsonEncode(self.custom.defaultItem))
		item["header"]["content"]["viewParams"]["categoryId"] = c["id"]
		item["body"]["viewParams"]["categoryId"] = c["id"]
		item["expanded"] = self.props.items[i].expanded
		items.append(item)
		
	return items

```

I encode the default structure saved in custom in JSON then decode it, replace the categoryId to the right id.

Edit : I also keep the expanded sections expanded by copy the current state to the new.

Thanks for your help ! 👋
