# Perspective: onChange script vs binding graph for multiple derived properties — which approach scales better?

**URL:** <https://forum.inductiveautomation.com/t/perspective-onchange-script-vs-binding-graph-for-multiple-derived-properties-which-approach-scales-better/115548>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [May 15, 2026, 12:58pm UTC](https://forum.inductiveautomation.com/t/perspective-onchange-script-vs-binding-graph-for-multiple-derived-properties-which-approach-scales-better/115548 "2026-05-15T12:58:37Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![hkewalramani](https://avatars.discourse-cdn.com/v4/letter/h/e47774/32.png) [@hkewalramani](https://forum.inductiveautomation.com/u/hkewalramani)\
**Post date:** [May 15, 2026, 12:58pm UTC](https://forum.inductiveautomation.com/t/perspective-onchange-script-vs-binding-graph-for-multiple-derived-properties-which-approach-scales-better/115548/1 "2026-05-15T12:58:37Z")

</div>

I have a Perspective view that receives data as a parameter. From that single source, I need to derive several custom properties — processed data, validation results, and state flags.

I'm trying to decide between two approaches:

**Option A — Single onChange script**  
All derived properties are set inside one `params.value` onChange handler. One execution, explicit order, easy to read top-to-bottom.

**Option B — Binding chain**  
Each custom property has its own binding with a script transform. The chain looks like this:

- `custom.A` → bound to `params.value`, script transform decodes/normalizes the raw data

- `custom.B` → bound to `custom.A`, script transform runs validation and returns a result object

- `custom.C` → bound to `custom.B`, transform extracts a boolean flag from the result

- `custom.D` → bound to `custom.A` + operator input, determines whether a change was made

- Button `enabled` → bound to `custom.C` + `custom.D`

Fully declarative — each property is self-contained and updates automatically when its source changes.

**Where I have concerns with Option B:**

As the chain grows deeper (A → B → C → UI state), it becomes harder to trace why a UI element is in a certain state — you have to open each property's binding individually. With Option A, you read one script top-to-bottom.

**My questions:**

1. Does Perspective guarantee evaluation order when a binding change cascades through a chain like A → B → C, or can you hit a state where C reads B before B has finished updating from A?

2. At what complexity — number of derived properties or chain depth — does one approach clearly win over the other?

3. Any general best practice for this pattern in Perspective?

---

<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:** [May 15, 2026, 1:08pm UTC](https://forum.inductiveautomation.com/t/perspective-onchange-script-vs-binding-graph-for-multiple-derived-properties-which-approach-scales-better/115548/2 "2026-05-15T13:08:41Z")

</div>

1. No order guarantees.

2. Any jython is a performance suck, and binding transforms also have overhead.

3. 

I would architect those dependant properties as subprops of another. So, `custom.group.A`, `custom.group.B`, et cetera, with a single expression binding, using my Integration Toolkit, like so:

```python
transform(
    {view.params.value},
    asMap(
        'A', ...nested expression using value()...,
        'B', ...nested expression using value()...,
        'C', ...nested expression using value()...,
        'D', ...nested expression using value()...
    )
)

```

Very similar to an expression structure binding, but fully atomic with my [transform()](https://www.automation-pros.com/toolkit/doc/utility.html#transform) expression function, and doesn't have any native transform overhead.

When parts depend on other parts, you can nest `transform()` to capture subexpressions. Perhaps like so:

```python
transform(
    ...expression A using {view.params.value}...,
    transform(
        asList(
            ...expression B using value()...,
            ...expression D using value() and {view.custom.operatorInput}...
        ),
        transform(
            ...expression C using value()[0]...,
            asMap(
                'A', value(2),
                'B', value(1)[0],
                'C', value(),
                'D', value(1)[1]
            )
        )
    )
)

```
