# Perspective Tree - restore tree expansion after self.refreshBinding("props.items")

**URL:** <https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [May 19, 2022, 1:29pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779 "2022-05-19T13:29:23Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [May 19, 2022, 1:29pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/1 "2022-05-19T13:29:24Z")

</div>

Ignition V8.1.15

I need to refresh the tree to eliminate the branch if it is now empty or add a new branch if one has been created.  
The problem is that the tree collapses so the user has to navigate the tree again.

The _onClick_ event in the refresh button below is intended to refresh the binding and re-expand the selected branch of the two-level tree.

```auto
	self.getSibling("Tree").refreshBinding("props.items")
	x = int(self.getSibling("Tree").props.selection[0].split('/')[0])
	self.getSibling("Tree").props.items[x].expanded = True

```

![Tree binding refresh 1](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/5/e550e67c1f41fc0e5f85ac07cb4c67e836cb56a3.gif)

Note that it works if I refresh several times.

Can anyone explain why it doesn’t work on every click?

---

<div class="post-metadata">

**Author:** ![code\_skin](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@code\_skin](https://forum.inductiveautomation.com/u/code_skin)\
**Post date:** [May 19, 2022, 1:31pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/2 "2022-05-19T13:31:50Z")

</div>

First thing that comes to my mind is, what is the props.items bound to?

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [May 19, 2022, 1:34pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/3 "2022-05-19T13:34:51Z")

</div>

For demo purposes it’s bound to an expression binding `null` with a script transform to return the items dictionary object.

> **Binding dictionary object**
>
> ```auto
> true = True
> false = False
> 	
> return [
> {
> "label": "Building 1",
> "expanded": false,
> "data": "",
> "items": [
> {
> "label": "Line #13",
> "expanded": false,
> "data": {
> "location": "Building_1",
> "equipment": "Line #13"
> },
> "items": []
> },
> {
> "label": "Line #14",
> "expanded": false,
> "data": {
> "location": "Building_1",
> "equipment": "Line #14"
> },
> "items": []
> },
> {
> "label": "Line #15",
> "expanded": false,
> "data": {
> "location": "Building_1",
> "equipment": "Line #15"
> },
> "items": []
> },
> {
> "label": "Line #17",
> "expanded": false,
> "data": {
> "location": "Building_1",
> "equipment": "Line #17"
> },
> "items": []
> },
> {
> "label": "Line #18",
> "expanded": false,
> "data": {
> "location": "Building_1",
> "equipment": "Line #18"
> },
> "items": []
> }
> ]
> },
> {
> "label": "Building_2",
> "expanded": false,
> "data": "",
> "items": [
> {
> "label": "Line #23",
> "expanded": false,
> "data": {
> "location": "Building_2",
> "equipment": "Line #23"
> },
> "items": []
> },
> {
> "label": "Line #24",
> "expanded": false,
> "data": {
> "location": "Building_2",
> "equipment": "Line #24"
> },
> "items": []
> },
> {
> "label": "Line #25",
> "expanded": false,
> "data": {
> "location": "Building_2",
> "equipment": "Line #25"
> },
> "items": []
> },
> {
> "label": "Line #27",
> "expanded": false,
> "data": {
> "location": "Building_2",
> "equipment": "Line #27"
> },
> "items": []
> },
> {
> "label": "Line #28",
> "expanded": false,
> "data": {
> "location": "Building_2",
> "equipment": "Line #28"
> },
> "items": []
> }
> ]
> }
> ]
> '''
> 
> ```

So the binding data never changes.

If you’d like to test it then create a coordinate view and drop these two items into it.

> **Tree**
>
> ```auto
> [
> {
> "type": "ia.display.tree",
> "version": 0,
> "props": {
> "selection": [
> "1/2"
> ],
> "selectionData": [
> {
> "itemPath": "1/2",
> "value": {
> "equipment": "Line #25",
> "location": "Building_2"
> }
> }
> ],
> "appearance": {
> "expandIcons": {
> "collapsed": {
> "path": "material/arrow_right"
> },
> "expanded": {
> "path": "material/arrow_drop_down"
> }
> },
> "defaultNodeIcons": {
> "expanded": {
> "path": "material/folder_open"
> },
> "collapsed": {
> "path": "material/folder"
> },
> "empty": {
> "path": "material/stop"
> }
> }
> },
> "style": {
> "borderStyle": "solid",
> "borderWidth": 1,
> "borderColor": "#81F68A"
> }
> },
> "meta": {
> "name": "Tree"
> },
> "position": {
> "x": 60,
> "y": 136,
> "height": 200,
> "width": 305
> },
> "custom": {},
> "propConfig": {
> "props.items": {
> "binding": {
> "type": "expr",
> "config": {
> "expression": "null"
> },
> "transforms": [
> {
> "code": "\ttrue = True\n\tfalse = False\n\t\n\treturn [\n\t {\n\t \"label\": \"Building 1\",\n\t \"expanded\": false,\n\t \"data\": \"\",\n\t \"items\": [\n\t {\n\t \"label\": \"Line #13\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_1\",\n\t \"equipment\": \"Line #13\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #14\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_1\",\n\t \"equipment\": \"Line #14\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #15\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_1\",\n\t \"equipment\": \"Line #15\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #17\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_1\",\n\t \"equipment\": \"Line #17\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #18\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_1\",\n\t \"equipment\": \"Line #18\"\n\t },\n\t \"items\": []\n\t }\n\t ]\n\t },\n\t \t {\n\t \"label\": \"Building_2\",\n\t \"expanded\": false,\n\t \"data\": \"\",\n\t \"items\": [\n\t {\n\t \"label\": \"Line #23\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_2\",\n\t \"equipment\": \"Line #23\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #24\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_2\",\n\t \"equipment\": \"Line #24\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #25\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_2\",\n\t \"equipment\": \"Line #25\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #27\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_2\",\n\t \"equipment\": \"Line #27\"\n\t },\n\t \"items\": []\n\t },\n\t {\n\t \"label\": \"Line #28\",\n\t \"expanded\": false,\n\t \"data\": {\n\t \"location\": \"Building_2\",\n\t \"equipment\": \"Line #28\"\n\t },\n\t \"items\": []\n\t }\n\t ]\n\t }\n\t]",
> "type": "script"
> }
> ]
> }
> }
> }
> }
> ]
> 
> ```

> **Button**
>
> ```auto
> [
> {
> "type": "ia.input.button",
> "version": 0,
> "props": {
> "text": "Refresh"
> },
> "meta": {
> "name": "Button"
> },
> "position": {
> "x": 285,
> "y": 346,
> "height": 34,
> "width": 80
> },
> "custom": {},
> "events": {
> "dom": {
> "onClick": {
> "type": "script",
> "scope": "G",
> "config": {
> "script": "\tself.getSibling(\"Tree\").refreshBinding(\"props.items\")\n\tx = int(self.getSibling(\"Tree\").props.selection[0].split('/')[0])\n\tself.getSibling(\"Tree\").props.items[x].expanded = True"
> }
> }
> }
> }
> }
> ]
> 
> ```

---

<div class="post-metadata">

**Author:** ![code\_skin](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@code\_skin](https://forum.inductiveautomation.com/u/code_skin)\
**Post date:** [May 19, 2022, 1:46pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/4 "2022-05-19T13:46:30Z")

</div>

Thanks. I tested and it looks like a classic race condition. Try this refresh button, it works every time for me. Based on this I think it’s safe to say refreshBinding works asynchronously and sometimes your expand logic would fire too quick.

```auto
[
  {
    "type": "ia.input.button",
    "version": 0,
    "props": {
      "text": "Refresh"
    },
    "meta": {
      "name": "Button"
    },
    "position": {
      "x": 285,
      "y": 346,
      "height": 34,
      "width": 80
    },
    "custom": {},
    "events": {
      "dom": {
        "onClick": {
          "type": "script",
          "scope": "G",
          "config": {
            "script": "\tself.getSibling(\"Tree\").refreshBinding(\"props.items\")\n\tx = int(self.getSibling(\"Tree\").props.selection[0].split('/')[0])\n\timport time\n\ttime.sleep(.1)\n\tself.getSibling(\"Tree\").props.items[x].expanded = True"
          }
        }
      }
    }
  }
]
```

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [May 19, 2022, 1:49pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/5 "2022-05-19T13:49:54Z")

</div>

You could probably also avoid the need for a delay if you put the expand logic inside the binding (that is getting refreshed.  
Since it seems like it will always look to the selection anyways.

```auto
items [
	  {
	    "label": "Building 1",
	    "expanded": false,
	    "data": "",
	    "items": [
	      {
	        "label": "Line #13",
	        "expanded": false,
	        "data": {
	          "location": "Building_1",
	          "equipment": "Line #13"
	        },
	        "items": []
	      },....
	     ]
	    if (self.props.selection[0]):
	       x = int(self.props.selection[0].split('/')[0])
	       items[x].expanded = True
	    return items

```

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [May 19, 2022, 2:41pm UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/6 "2022-05-19T14:41:08Z")

</div>

> [@code\_skin](#):
>
> I think it’s safe to say refreshBinding works asynchronously and sometimes your expand logic would fire too quick.

I had thought it might be that.

I'm going to go with @victordcq and modify the binding and re-enable the expanded rung. It's a bit more elegant and will make it look like I know what I'm doing.

Excellent response times, guys. Thank you both.

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [May 20, 2022, 6:29am UTC](https://forum.inductiveautomation.com/t/perspective-tree-restore-tree-expansion-after-self-refreshbinding-props-items/59779/7 "2022-05-20T06:29:24Z")

</div>

> [@Transistor](#):
>
> will make it look like I know what I’m doing.

xD
