Perspective relative references to parent component properties

It would seem as though I’m a bit confused how relative referencing works in Perspective.

For example:

Given this component structure
image

Below are the expressions to access each level of component’s meta.name property, from the view.root.root_0.CoordinateContainer.foi level:

{/root.meta.name} 		// view.root.meta.name
{..../root_0.meta.name}	// view.root.root_0.meta.name
{parent.meta.name}		// view.root.root_0.CoordinateContainer.meta.name
{this.meta.name}		// view.root.root_0.CoordinateContainer.foi.meta.name

It looks like {../../../root.meta.name} syntax works as well

Why is every level so different?
Why can’t I use {parent.parent.parent.meta.name} to get to the view.root?
Why can’t I use {....../root.meta.name} to get to view.root?

I just want to be able to consistently know how to relatively traverse the components in the expression language without having to name a component e.g. parent.parent.parent.meta.name is what I would like to use.

2 Likes

Bump

:frowning:
does anyone know about this?

Honestly, I’m as confused as you are.

I believe i once saw a topic about this wierd interaction, but i dont seem to find it again immediatly.
And i dont recall what was said there xd
edit: found it:

have you tried this?
https://docs.inductiveautomation.com/display/DOC81/property

(no idea if it helps tho)

Thanks (that topic title is a bit cryptic - probably why I didn’t find it :thinking:)
I haven’t tried using property but I presume it’ll have the same limitations, i’ll still give it a go though. I can’t use - or rather I don’t want to use script bindings as I’m trying to increase performance not reduce it - in this instance as it will be used in a lot of places.

What I wanted to attempt to do, as a test for curiosity more than anything, was to write a script to “flatten” a view and save it as a new view. When I say “flatten” I mean replace all embedded views with their basic components to see if this increases the load speed of some of our views. To do this however, I need to remap all bindings on embedded views that use the view.custom / view.params properties. I was hoping that I could simply use {parent.parent…etc} to do that, but it seems not :frowning: so I’m going to have to use some weird case logic to do it instead and use a completely different expression for each level I want to go down, which is far from ideal

I seem to remember a post by someone from IA mentioning they were thinking about ‘flattening’ views on the server side. I wonder if that’s something we’ll see…

1 Like

Nah, they gave up/found it wasn’t viable last I heard. I don’t know what the reason was… to be honest, it doesn’t seem that difficult albeit a little time consuming. I’m sure when/if I get to it, I may run into hurdles :man_shrugging: I’m curious what the result will be though and if it’ll be worth the trouble at the end of it

Ah is script less performant than expression then?

Im not to busy with that. What i did notice is that flexrepeaters are really slow, it gets really obvious if you give it a high number. So i assume all embdedded views suffer from this a little bit.

We wanted to use a flex repeater to “draw” out a storage and have a view for each possible location. This worked decently in vision but was so slow in perspective, that i made a module for the company to draw out the storage. The performance improvement was insane.

I guess like almost everything you can only choose 2 of the 3
Quality, speed, price

There's the overhead of loading the interpreter, and I'm guessing expressions are also easier and faster to parse.

Oh, well its not something we notive here. We use scripting a lot.
Or maybe that was one of the causes that the flex repeater also went super slow idk.

I’m pretty sure in most cases it’s not noticeable, but it’s something to keep in mind: If you can do it in an expression, might as well do that.

1 Like

Yes, quite significant.

Not parsed at execution time. They are parsed or deserialized once at tag/binding startup. Pure java method execution after that. No overhead, no interpretation.

3 Likes

I just wanted to bump this again and see if anyone from IA can comment on the OP, and whether relative referencing can be made simpler and consistent? i.e. being able to address subsequent parents using either

parent.parent.parent.custom.prop1
../../../.custom.prop1
# or similar

instead of having to explicitly name them (which defeats the purpose of using relative referencing)

Sad face :frowning:

Perhaps call out people from IA, put them on the spot, like @PGriffith, @ggross @cmallonee :slight_smile:

1 Like

This is about as much as I know:
https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.19/com/inductiveautomation/perspective/gateway/property/PropertyReference.html

This is a deep, fundamental piece of Perspective that I had no hand in, so I can’t speak as to why any of this is the way it is.

So, as best I can understand it (which isn’t much :man_shrugging:t2: ) You start with .. and then each parent container you want to traverse up the tree, adds another single . Or you can also use, ../.

Basically: Both .. and ../ move the point of reference to the parent container. Once there you can move to the next parent with either a single . or ../.

Some examples.

Say you have a structure of nested containers:

root
->Parent 1
->->Parent 2
->->->PeerComp
->->->ThisComp
->->Parent 3
->->->OtherComp

Example 1
To reach a custom property on PeerComp in a binding from ThisComp then you would use the following.

../PeerComp.custom.prop1

The ../ places you in the point of reference of Parent 2 Then you provide a valid Property Identifier

Example 2
To reach a custom property on Parent 2 in a binding from ThisComp then you would use the following.

../../Parent 2.custom.prop1 or .../Parent 2.custom.prop1

The first ../ from the property identifier puts you in the point of reference of Parent 2, as in Example 1, you can then use either another ../ or just . to put you in the point of reference of Parent 1. To be valid property identifiers must be of the form <name>.<scope>.<property_identifier>, so you must traverse far enough up the tree to reference the component by name (e.g. the components parent).

Example 3
To reach a custom property on Parent 1 in a binding from ThisComp then you would use the following.

../../../Parent 1.custom.prop1 or ..../Parent 1.custom.prop1

This is just a continuation of example 2. For each parent that you need to traverse up the tree you add either another ../ or . So two dots to get to the parent of this component and then an additional dot for each parent up the tree.

Example 4
Finally, if you need to get to the root then just a single / can be used. Essentially this puts you in the point of reference of the View, so To reach a custom property on root in a binding from any component then you would use the following.

/root.custom.prop1

Finally, you can only use the dot notation to travers up the tree, to come back down you must then use an absolute path. For instance, to reach a custom prop on PeerComp in a binding from OtherComp you could use the following.

.../Parent 2/PeerComp.custom.prop1

So all of that just to work through the Relative path prefix syntax.

On top of this there is also, the Absolute path prefix type, which is as you might expect the path in reference to the View, and the Shortcut path prefix type, which is the this, view, parent type paths.

Basically, the Shortcut’s are exactly that named replacements for common paths. So parent always takes you to the parent of the component you’re working with, view always takes you to the view that you are working with, and this is always to this component.

So working with our example structure we can see that

parent.custom.prop1 is equal to .../Parent 2.custom.prop1. So you could say that
parent = .../parentName

In the same way, this.custom.prop1 is equal to ../ThisComp.custom.prop1. So you could say that
this = ../componentName

However, you can’t use / or . in a shortcut prefix, so for instance from OtherComp the path
parent/Parent 2/ThisComp.custom.prop1 is invalid. This is why, parent.parent.* doesn’t work.

Instead you would need to use either the Absolute path /root/Parent 1/Parent 2/ThisComp.custom.prop1 or the Relative path
.../Parent 2/ThisComp.custom.prop1.

The only thing left of note, is that “as far as I can tell” there is no relative path that will reach the view, so the only way to reach properties on the view is to use view.custom.prop1. Likewise the only way to reach properties on the root is to use an Absolute path /root.custom.prop1.

6 Likes

The answer provided by @lrose is pretty much textbook perfection. I don't really have much to add.

I guess I can try to answer these original questions:

The answers for these questions are essentially "because that's how we programmed it".

The idea here was that the syntax was {../locate/the/component DOT scope DOT property path} We use shortcuts plus filesystem-style slash-based tree traversal syntax to get to the target component, and then we use dots to get into the property namespace. This keeps the path parsing deterministic.

Why is every level so different?

Is it? I don't think so. You have 1) direct keyword-orient shortcuts (this, parent, view, session, and page), you have "go up X levels from here", and you have "start at the top".

Why can't I use parent.parent.parent...

We didn't want to overload the use of dot-dereferencing because that would have led to confusing and in some cases non-deterministic path parsing. If we allowed parent.parent.parent.scope.path it would also invite the syntax of parent.parent.child.child.scope.path that is - to use the dot separator to walk up and down the component tree. If we do that, it becomes difficult to determine when the "component path" bit ends and the "scope.path" bit begins. You'd be hosed if you had a component named "meta", for example.

Why can't I use ......./root

Well this is a bit of a curiosity due to our implementation. The root container is actually the top of the component heirarchy. The view is sort of special and not actually a component, so it's a bit of an outlier. I can understand that this might feel inconsistent, but that's just the way it is.

2 Likes

Why would Ignition throw an expression error for these relative references when i've picked the property from the property browser...?
This is maddening.

Property browser trying to configure a Property binding on a basic label component:
image

Path provided by Ignition, which makes sense based on the comments above..
image

Binding doesn't work..
image

Different behavior when i use an Expression binding instead:
image
image
image