# Accessing document custom tag property members the same way as document tag members

**URL:** <https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348>\
**Category:** Ignition\
**Created:** [March 28, 2025, 1:11am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348 "2025-03-28T01:11:58Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 1:11am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/1 "2025-03-28T01:11:58Z")

</div>

Any consideration around accessing “document” tag custom property _members_ via `UDTi_or_Atomic_tagPath.custom_prop[“member”]` like `document_tag[“member”]` in ~~expressions~~ tag bindings?

I understand they’re different object types and document tag members are nested under a “value” key whereas document custom property members don't… but this would be a HUGE deal and incredibly simplify (or completely remove the need for) expression transforms on tag bindings just to read the value of document custom tag properties.

Example: I store “user friendly” strings that correspond to Boolean tag states in a bool\_state document custom property on each Boolean tag. I currently have to read the custom property via tag binding and then extract the members via expression transform. Could be done with a tag binding alone if this was supported.

Of course, please school me if I’m missing something

---

<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:** [March 28, 2025, 1:40am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/2 "2025-03-28T01:40:48Z")

</div>

> [@hunterdg](#):
>
> Of course, please school me if I’m missing something

You are using the tag function outside of expression tags. Even if this feature was implemented, doing it inside the `tag()` function is crazy talk. You should pitch it as a generic extension to tag paths in general, and then your indirect binding could use it, along with all of the other places in Ignition that accept tag paths.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 2:05am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/3 "2025-03-28T02:05:00Z")

</div>

> [@pturmel](#):
>
> You are using the tag function outside of expression tags

~~I’m trying to understand, need some help~~

~~It’s bad (i know it’s not ideal) to use `tag()` in perspective property expression bindings/transforms? Is the alternative multiple properties each with tag bindings and an additional property to compse the desired result?~~ That gives me the ick. EDIT: (but i get it now)

~~is an expression structure binding with multiple tag() functions, then a transform to compose desired result any better? (no)~~

EDIT: suppose I should’ve just omitted the `tag()` bit - (but it was useful to pull out a single prop in the middle of a transform)

> [@pturmel](#):
>
> Even if this feature was implemented, doing it inside the `tag()` function is crazy talk

to be clear, `tag('document_tag[“member”]')` does indeed work, as does a tag binding to just `document_tag[“member”]`

> [@pturmel](#):
>
> generic extension to tag paths in general

I’m definitely all for this, and naively thought it was implemented as such when i discovered it yesterday, only to be disappointed (I have a unique situation where I’m using a real document tag as opposed to document custom tag properties)

I’m all in on document custom tag properties as an effective DB metadata and “static” tag parameter alternative, so if I’m missing something, please let me know

Is my current method of just reading the whole custom tag property and then parsing it via expression transforms really the most performant/effective?

is a tag binding to `document_tag[“member”]` less performant if I only need one “member”?

---

<div class="post-metadata">

**Author:** ![bmusson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmusson/32/87530_2.png) [@bmusson](https://forum.inductiveautomation.com/u/bmusson)\
**Post date:** [March 28, 2025, 2:28am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/4 "2025-03-28T02:28:38Z")

</div>

> [@hunterdg](#):
>
> Is my current method of just reading the whole custom tag property and then parsing it via expression transforms really the most performant/effective?

Depends on how big the document tag is. If it’s got 1000 keys and you only need to access 2 for your UI, then it’s probably overkill.

But if it’s a reasonably sized object I’d expect this to be the most performant. If you don’t want the whole object to be sent to the client you can always set its access to Private.

---

<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:** [March 28, 2025, 11:40am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/5 "2025-03-28T11:40:41Z")

</div>

> [@bmusson](#):
>
> set its access to Private.

You should do this for almost all custom properties.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 4:39pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/6 "2025-03-28T16:39:49Z")

</div>

somewhat on this same subject - I’m using the results of system.tag.query to populate the instances of a “Label” flex-repeater. I ensure the query includes/returns the basic ’static’ properties from each tag like engUnit, formatString, whatever custom tag properties I need, etc so I can compose the label text with relevant data. Same goes for other “base” view “templates”

I’m a big fan of reusability so I also embed the same “base” view in table cells where applicable (to allow for realtime tag updates). to allow for this, each base view (that might also be embedded in a table cell) has at least two view param _objects_: `view.instanceData` (for flex repeater embedding) and `view.rowData` (for table cell embedding) - and occasionaly `custom.urlParams`.

I “templataize" the contents of each object to match the expected runtime contents (in _replace_ mode) of each embedding method’s parameters - implicit or otherwise (as well as i can, primarily for debugging and ease of future maintenance/development by other folks), **but notably** I set each and every value to `null` (this is often unexpected by other folks, but I develop with an expectation of default nulls/to ensure `null` cases are appropriately handled).

Where I can, I enable “static” expression structure bindings (transient, with `null` for each value, and with comments where useful) on these _input_ view parameter objects to ensure debug/testing values are not saved with the view, but this is not always feasible as even default/static `null` bindings do not always get overridden on view intialization (I still create the bindings for reference but disable them in these cases). I haven’t taken the time to nail down every scenario that causes this, but it’s definitely related to my method of coalescing multiple “identical” parameters from different sources with different embedding methods.

I then create dedicated `custom._coalesced` parameter objects (with per-member `coalesce()` expression bindings - or just a top-level expression structure binding with multiple `coalesce()` expressions) to compose the actual desired values. All other bindings in the views reference these **coalesced** parameters instead of the view params

**here’s the meat of my question:**  
In the `instanceData` (flex repeater) case where tag properties like engUnit/formatString/custom\_prop are easily sourced (and passed in) by the results of a `system.tag.query()` pointing at a single site/device parent tagPath, the `custom._coalesced` function has an easy job, but in the `rowData` (table cell embedding) case (which is an ‘overview’ displaying a subset of values for _every_ site/device) I don’t readily have that data available so I must do tag reads based on `rowData.fullPath` (into a `custom._tagReads` property object with individual member indirect tag bindings) for the `custom._coalesced` object to reference

few questions:

- is the single-universal-“base template”-view method overkill? Should I just create different ‘base’ views for each embedding method?
  - admittedly it may sometimes take more effort to cordinate between multiple identical ‘base’ params in a single view

- i’ve considered doing a recursive tag query for the “overview” table situation, or multiple per-row (site/device) targeted tag queries and stuffing that data into a hidden column for the implicit `rowData` view param to pass into the nested cell views, but that feels wrong - shouldn’t the underlying queries for a table be as light as possible? Surely a couple tag reads are better than even a tightly filtered recusrive tag query
- is this method overly-flexible? Should I just abandon querying/passing in the requisite additional ’static’ tag properties in the `instanceData` (flex-repeater) scenario in favor of indirect-tag-bindings (only)?
  - this is admittedly relatively easier, and it’s how I historically developed - assuming only a tagPath would ever get passed in to any nested view, but that was back when we only had `system.tag.getConfiguration` and `system.tag.browse()`

- of course general feedback

---

<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:** [March 28, 2025, 5:10pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/7 "2025-03-28T17:10:55Z")

</div>

You just need my `pageVarMap()` functions from my Integration Toolkit. Add a change event to the coalesced parameter object and write into the `pageVarMap()` (and then fire its refresh method). All of your nested views will then be able to use a `pageVarMap()` expression function to obtain the same structure, and extract any instance-specific values.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 6:59pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/8 "2025-03-28T18:59:11Z")

</div>

just realized my presumed legitimate rationale for using `tag()` in expression binding:

presumably `coalesce({value}, tag(‘tagPath’))` will completely avoid reading the tag if `{value}` is not null..

if I instead coalesce two distict properties (the latter with a tag binding), there’s an unavoidable read to a (possibly nonexistent) tag

thoughts? Is this unavoidable read to a possibly nonexistent tag preferable to a an expression `tag()` read only when required? I’d argue the answer would intially be “no” if one was unaware of the performance ramifications, and only “maybe” if one (like me) was only vaguely aware that it’s less than ideal, and assumed the majority of cases would result in the coalescing of an existing value rather than a tag read.

ugly compromise on it’s face IMO. (apologies if this has been hashed out before as I imagine it has)

p.s. just pulled down the Integration Toolkit. Does the modbus driver support Enron/7x registers?

---

<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:** [March 28, 2025, 7:23pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/9 "2025-03-28T19:23:30Z")

</div>

> [@hunterdg](#):
>
> presumably `coalesce({value}, tag(‘tagPath’))` will completely avoid reading the tag if `{value}` is not null..

No, it won't. It will still subscribe to the tag, even though the values will be discarded. And updates to the tag will cause the expression to re-execute, even if it will discard again.

Really, do not use the `tag()` expression function in UI bindings. **Ever**.

> [@hunterdg](#):
>
> Does the modbus driver support Enron/7x registers?

No. Not enough commercial interest for me to spend the time to support Enron format.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 7:54pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/10 "2025-03-28T19:54:06Z")

</div>

> [@pturmel](#):
>
> cause the expression to re-execute

just to be clear, if any referenced value in a coalesce function changes, the expression re-executes, but retains the first non-null value’s data - **and timestamp**?

in other words, there’s no obvious “evidence” that the expression has re-executed but bailed before returning?

i assumed (there i go again) it perhaps subscribed to the parameters in order, and only re-executed if preceding parameters became non-null or if the current value became null

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [March 28, 2025, 7:58pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/11 "2025-03-28T19:58:22Z")

</div>

> [@hunterdg](#):
>
> just to be clear, if any referenced value in a coalesce function changes

if any referenced value in **any** expression changes, the expression re-executes.

---

<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:** [March 28, 2025, 7:58pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/12 "2025-03-28T19:58:57Z")

</div>

> [@hunterdg](#):
>
> but bailed before returning?

It doesn't "bail".

When the expression is first started, before evaluation, the `tags()` expression gets connected to the tag subsystem. If coalesce's first argument is null at any point, the `tag()` expression will evaluate its path and subscribe to it. Thereafter, the entire expression will re-execute as that tag updates, even if the coalesce never evaluates that part again.

Since UI properties often start with a null, the odds of this scenario are very high.

Don't use `tag()` in UI expressions. **Ever**.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 8:03pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/13 "2025-03-28T20:03:19Z")

</div>

> [@pturmel](#):
>
> do not use the `tag()` expression function in UI bindings. **Ever**

another use case - i need to chose from a list of n tags based on their quality - if the first is bad, i need to move on to the next.

without `tag()` i’d need to hardcode n properites with tagbindings and evaluate their qualities in a giant case statment

i guess i could just script out the — no that’s assuming i would want to pick the first tag that is good and stick with it, unless i set up a timer to re-execute the “pathPicker” script.

wow this is good exercise for alternative (but likely more complex) problem solving

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [March 28, 2025, 8:05pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/14 "2025-03-28T20:05:47Z")

</div>

> [@hunterdg](#):
>
> another use case - i need to chose from a list of n tags based on their quality - if the first is bad, i need to move on to the next.

`tags()` expression selecting 1st where quality is good using Integration Toolkit. (Doesn't have pitfalls of `tag`)

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 28, 2025, 8:06pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/15 "2025-03-28T20:06:32Z")

</div>

i guess i just need to suck it up and use the toolkit (and help push my clients)

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [March 28, 2025, 8:07pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/16 "2025-03-28T20:07:22Z")

</div>

You get a lot of bang for your buck($0)

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [March 28, 2025, 8:07pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/17 "2025-03-28T20:07:23Z")

</div>

> [@hunterdg](#):
>
> i need to chose from a list of n tags based on their quality

You would read them all in at once in a script, then you could easily filter out non-good quality.

```python
values = [qv.value for qv in system.tag.readBlocking([tagPaths]) if qv.good]

```

Highly recomend the the toolkit though, it is well worth the "Free" price tag.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 29, 2025, 6:35am UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/18 "2025-03-29T06:35:12Z")

</div>

> [@ryan.white](#):
>
> `tags()` expression selecting 1st where quality is good using Integration Toolkit. (Doesn't have pitfalls of `tag`)

might need some help.

appears `tags()` dosen’t return a QualifiedValue per-tag, but instead at the object level, with the quality of the last bad tag in the list. Unsure how I would use this to "select 1st where quality is good” inside an expression 😕 (but admittedly I just started poking around and prob need some sleep)

additionally, wrapping it in `forEach()` just returns a null QualifiedValue (with the same quality) if any of the tags are bad/don’t exist.

> **example binding**
>
> ```python
> {
> "type": "expr",
> "config": {
> "expression": "//typeOf(\r\n\tforEach(\r\n\t\t//tags({this.custom.paths}),\r\n\t\ttags(\r\n\t\t\tasList(\r\n\t\t\t\t\u0027DNE\u0027,\r\n\t\t\t\t\u0027badQuality\u0027,\r\n\t\t\t\t\u0027\u0027//,\r\n//\t\t\t\tnull\r\n\t\t\t)\r\n\t\t),\r\n\t\tit()[1]\r\n\t)\r\n//)\r\n"
> },
> "transforms": [
> {
> "code": "\treturn value,quality,timestamp",
> "type": "script"
> }
> ]
> }
> 
> ```

---

<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:** [March 29, 2025, 1:49pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/19 "2025-03-29T13:49:07Z")

</div>

Hmmm. I haven't anticipated this possible usage. I have recommended wrapping the output of `tags()` with `forceQuality(..., 192)` to deal with bad tags, but it turns out that wipes the qualities of nested values, too.

And you can't pass bad quality to my iterators--they bail out. Perhaps I should change that. Hold the line for a few....

Edit: _ **Ugly** _.

If I modify `tags()` to ignore the quality of the tag values for its own return quality, it will deliver the nested qualities. And you can iterate over the output of `tags()`. **However** , you can't get at those nested qualities in expressions. The square bracket operator discards the quality of the retrieved value. And worse, Perspective itself will discard the nested qualities when it constructs its internal property representation. You can use the dataset form of `tags()`, and Perspective will hold the dataset with qualities intact, but only scripting can access them.

I will pitch to IA to have the subscript operator deliver nested quality, but that probably wouldn't be acceptable before v8.3, and would need some risk assessment. Perhaps I should implement a quality-aware subscripting function.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [March 29, 2025, 4:06pm UTC](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348/20 "2025-03-29T16:06:06Z")

</div>

Would simply replacing tag() with tags() (in my prior use case) mitigate the problems with tag()?

I’d have to somehow handle copying the quality from the parent object into the [1]… but I feel like I was somehow able to retain the quality of a _single_ tag in an initial test.

(I’ve spent a whole day trying to refactor my tag() usage with indirect bindings, but haven’t been successful without a giant case statement)

More specifically - it’s easy to get the TAG with good quality, but not the tagPath that will result in good quality (without a tag()) function). I need the “good” tagPath to derive the appropriate engUnits/formatString/custom props

Unless there’s some way to derive the path from a tag binding within an expression transform on said tag binding

I haven’t tried coalesce(tags(1), tags(2)…) but I don’t think that would work

[Next page](https://forum.inductiveautomation.com/t/accessing-document-custom-tag-property-members-the-same-way-as-document-tag-members/104348.md?page=2)
