[BUG] Bindings on props within array items don't stay with their associated array item if moved to a new array index

Hello,

I’m encountering a bug and didn’t know where to report it. It’s easy enough to work around, so I didn’t bother submitting a support ticket.

I have some parameters I’m passing to an embedded view (using perspective). These parameters include an array of objects:

One of these objects (object 4) has a binding on one of its values (position). If I duplicate an object above object 4, Ignition appropriately increments the number of the objects below where the duplicated object is, however the binding doesn’t shift down with the object. See the following screenshot after I duplicate object 2:

As you can see, object 2 is duplicated, the object that was previously object 3 is now object 4, and object 4 is now object 5. However the binding that was present on object 4 remained in place rather than shifting down with the object.

This is easy enough to work around by copying the binding, pasting it where desired and deleting the out-of-place binding.

Ignition Version: 8.0.5-rc1 (b2019100115)**

Regards,
Wade

I would believe this is expected behavior. Just as a binding in an object is associated with a specific key, a binding in an array is associated with a specific index. It’s not possible to create/move bindings dynamically, and the bindings on the component are not determined by the data IN the json, but the definition OF the json. This can be more easily understood by taking a look at the json file that determines how each view is built.

As an example lets take a scenario with a simple binding, on a menu tree’s props.items[0].target property. All it does is return “/Home”


And then a simple binding on the position.grow property, that returns 0

If we take a look at the view.json for that page, at the beginning of the json is a list of all the children in the root container like so:

"root": {
    "children": [
      {
        "meta": {
          "name": "MenuTree"
        },
        "position": {
          "basis": "523px"
        },
        "propConfig": {
          "position.grow": {
            "binding": {
              "config": {
                "expression": "0"
              },
              "type": "expr"
            }
          },
          "props.items[0].target": {
            "binding": {
              "config": {
                "expression": "\u0027/Home\u0027"
              },
              "type": "expr"
            }
          }
        },

If you notice on the menu tree item, under propConfig (the bindings), you have two dictionaries listed, one for position.grow and one for props.item[0].target. As you can tell here they are defined with specific locations in the overall JSON, but are unaware of the data that would end up being populated in that JSON. This is so you can know for certain where a binding will show up, no matter what the state of the page is.

I would say that in your case (If you potentially need this to be a bit more dynamic) you could create a binding that builds the entire props.params object dynamically, with the necessary logic for that position property defined in the script transform.

OR you could use a custom property that contains the same logic as your original binding, then add a script transform to iterate through that props.params.labelArray list and find the correct item and set the position there.

Hi Keith,

Thanks for the in-depth reply. Apologies if I didn’t make my post clear or if I’m misunderstanding your answer, but I’m not looking to dynamically create/move bindings during runtime. When I duplicated the item in the array, I was referring to right-clicking on the object in the property editor in designer and duplicating it there.

Your answer did make me go and have a look in the JSON and this is what I found. PS1_Geo_Button is the name of the embedded view that I have these parameters on.

Before duplicating the object in the array:

{
            "meta": {
              "name": "PS1_Geo_Button"
            },
            "position": {
              "height": 47,
              "width": 79,
              "x": 1216.796875,
              "y": 358.875
            },
            "propConfig": {
              "props.params.EngHigh": {
                "binding": {
                  "config": {
                    "fallbackDelay": 2.5,
                    "mode": "direct",
                    "tagPath": "[default]Pump Station 1/L01/L01/Process Value.EngHigh"
                  },
                  "type": "tag"
                }
              },
              "props.params.labelArray[4].position": {
                "binding": {
                  "config": {
                    "fallbackDelay": 2.5,
                    "mode": "direct",
                    "tagPath": "[default]Leachate Pond 1/Aerator/M04-LISP.value"
                  },
                  "type": "tag"
                }
              },
              "props.params.processValuePath": {
                "binding": {
                  "config": {
                    "fallbackDelay": 2.5,
                    "mode": "direct",
                    "tagPath": "[default]Pump Station 1/L01/L01/Process Value.path"
                  },
                  "type": "tag"
                }
              }
            },
            "props": {
              "params": {
                "fillColour": "#AC5F00",
                "labelArray": [
                  {
                    "in": false,
                    "label": "Inlet - xx m",
                    "position": 5,
                    "side": false
                  },
                  {
                    "in": false,
                    "label": "Top - 31.697 m",
                    "position": 100,
                    "side": true
                  },
                  {
                    "in": false,
                    "label": "Depth - 3.26 m",
                    "position": 100,
                    "side": false
                  },
                  {
                    "in": false,
                    "label": "Bottom - 0 m",
                    "position": 0,
                    "side": false
                  },
                  {
                    "in": true,
                    "label": "Aerator Inhibit SP",
                    "side": false
                  }
                ],
                "pitColour": "#AAAAAA",
                "title": "Pump Station 1"
              },
              "path": "Page/Embedded/Symbols/Geometric_Popup_Pit_Button"
            },
            "type": "ia.display.view"
          }

After duplicating the object in the array:

{
            "meta": {
              "name": "PS1_Geo_Button"
            },
            "position": {
              "height": 47,
              "width": 79,
              "x": 1216.796875,
              "y": 358.875
            },
            "propConfig": {
              "props.params.EngHigh": {
                "binding": {
                  "config": {
                    "fallbackDelay": 2.5,
                    "mode": "direct",
                    "tagPath": "[default]Pump Station 1/L01/L01/Process Value.EngHigh"
                  },
                  "type": "tag"
                }
              },
              "props.params.labelArray[4].position": {
                "binding": {
                  "config": {
                    "fallbackDelay": 2.5,
                    "mode": "direct",
                    "tagPath": "[default]Leachate Pond 1/Aerator/M04-LISP.value"
                  },
                  "type": "tag"
                }
              },
              "props.params.processValuePath": {
                "binding": {
                  "config": {
                    "fallbackDelay": 2.5,
                    "mode": "direct",
                    "tagPath": "[default]Pump Station 1/L01/L01/Process Value.path"
                  },
                  "type": "tag"
                }
              }
            },
            "props": {
              "params": {
                "fillColour": "#AC5F00",
                "labelArray": [
                  {
                    "in": false,
                    "label": "Inlet - xx m",
                    "position": 5,
                    "side": false
                  },
                  {
                    "in": false,
                    "label": "Top - 31.697 m",
                    "position": 100,
                    "side": true
                  },
                  {
                    "in": false,
                    "label": "Depth - 3.26 m",
                    "position": 100,
                    "side": false
                  },
                  {
                    "in": false,
                    "label": "Depth - 3.26 m",
                    "position": 100,
                    "side": false
                  },
                  {
                    "in": false,
                    "label": "Bottom - 0 m",
                    "side": false
                  },
                  {
                    "in": true,
                    "label": "Aerator Inhibit SP",
                    "position": null,
                    "side": false
                  }
                ],
                "pitColour": "#AAAAAA",
                "title": "Pump Station 1"
              },
              "path": "Page/Embedded/Symbols/Geometric_Popup_Pit_Button"
            },
            "type": "ia.display.view"
          }

I do notice that the bindings are stored separately inside “propConfig” rather than with the static properties in “props”. Is this what you meant by the bindings not being determined by the data IN the json (as the bindings are not stored in the labelArray json) but by the definition OF the json?

What I’m confused about is:

  1. Prior to my duplicating an object into labelArray, the “position” property in object 4 isn’t stored in “props” (As you’ve pointed out it has a binding on it so it’s stored in “propConfig”) - this is fine

  2. After duplicating an object the object (now object 5) now has a position property in “props”, so Ignition clearly recognises that this object has a position property even though it wasn’t listed in “props”. I imagine Ignition would have to see the property in “propConfig” to be aware of this. So then why doesn’t it update the property in “propConfig” to move the binding to the new array index?


Also, I’ve just noticed this bug (if it is a bug) only occurs when I duplicate an object in the array. If I delete an object, the binding moves correctly with the rest of the properties:

This screenshot was taken after:

  1. The binding was on “position” in array index 4
  2. I duplicated the object in index 2. Objects 3 and 4 incremented their index. The binding remained at array index 4
  3. I deleted the duplicated object in index 3. Objects 4 and 5 decremented their index. The binding moved from array index 4 to array index 3

Interesting I didn’t know this Is how the delete behavior worked, that might lead me to believe that the “duplicate” action should move it as well, I guess I’m not sure on that one.

Bumping this thread to see if we can get an official answer. Is this behavior a bug or should bindings move when deleting/inserting elements in an array?

I just found this out the hard way after deleting an array element in a flex repeater. Now all my bindings are messed up and I have to basically delete the entire thing and start over.

My flex repeater contained different types of views, so the structure of the parameters didn’t line up with the bindings when I deleted an element. Now some objects show they have a binding somewhere (highlighted in blue), but the parameter doesn’t exist, so I can’t get to the binding to remove it.

It would be nice if bindings moved with the elements of the array. Not sure if this is possible though.

Side note: It would be nice to have a “copy all child bindings” in the right click menu. It would make copying/pasting bindings in large objects much faster.

Looking for an answer to this as well. Seems like a bug to me. I should add that this also occurs when moving properties.

There’s another thread on this topic somewhere. Not handy, sorry. Bottom line: it is expected and fundamental behavior of bindings where an array is involved. The binding targets a specific subscript in the array. Move elements around and the binding is now pointing at the “wrong” element.

Don’t expect a fix any time soon, if ever.

If that is the case, why does it work correctly when deleting a property?

Before - Binding is on 4


After deletion - binding is on 3

Oh, you’ve change the problem description to designer editing behavior rather than runtime array changes. I agree that the designer should get it right–it knows what you are doing and should be able to adjust. At runtime, bindings are already “locked in”, so to speak.

Any updates on this one? @PGriffith
I forgot about this and created a new element inside of an embedded SVG, then shifted the item to the top to send it to the background, then all of my bindings on the items above it have now been shifted down. As you know, SVG elements are all completely different so replacing a binding on these with something random can completely ruin your SVG. Speaking of which, some of my bindings were manipulating the path “d” property… so now I stuffed up a whole number of SVG elements and can’t get it back :confused: I’m still in 8.1.5 though so hoping this is fixed in later versions?

PS. I’ve escalated this via my channels under support case 48851 as this can be particularly nasty when stung.

1 Like

This is still such a pain... I forgot about this, again, and just completely destroyed my SVG element d path bindings by moving elements with bindings in the array around... :confused: This is incredibly frustrating and seems like such a simple thing to fix in the code. Is this actually on a list to be fixed? And is there a scheduled version? I'm trying to think of a way I can do this in the meantime...

Aaaaaand I did it again :weary:

This is getting really old guys... and relatively easy for you guys to fix...

I have to move index 10 to index 1 and keep the bindings intact... yay, fun for me....... :face_with_symbols_over_mouth::face_with_symbols_over_mouth::face_with_symbols_over_mouth:

I'm going to schedule a weekly bump on my calendar

29 indexes to change when this should be done automatically :weary:

I really hope that the new drawing tool doesn't suffer from this issue!!!

Edit:
I've raised this as a bug through support, #98319

3 Likes

Just doing some testing and this bug still seems to not be fixed, four years later. @nminchin same for you?

I have to reorder a navigation menu tree to reflect changes in plant layout. The appropriate method seems to be to very carefully keep track of each reordering, copy+paste the bindings for all but one of the items, fully recreate the bindings on the last item then re-test the entire functionality.

Is there any better way to do this, am I missing something?

What version are you in? It was fixed I believe, don't recall version

I'm running 8.1.32. Tested using a new menu tree and the bindings definitely did not move with the item. Any chance you could run a quick test on whatever you're running?

This was fixed in Ignition 8.1.39

Garth

Awesome, thank you!