# Fill dropdown list with folder of tags

**URL:** <https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [July 2, 2021, 1:39pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457 "2021-07-02T13:39:22Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![theo](https://avatars.discourse-cdn.com/v4/letter/t/a87d85/32.png) [@theo](https://forum.inductiveautomation.com/u/theo)\
**Post date:** [July 2, 2021, 1:39pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/1 "2021-07-02T13:39:22Z")

</div>

Hi everyone,

I would like to know if it is possible to fill a dropdown list with a all the tags of a folder, I did not find the syntax of a loop to browse the tags of a folder

Thank you in advance for your help.

Théo.

---

<div class="post-metadata">

**Author:** ![jlandwerlen](https://avatars.discourse-cdn.com/v4/letter/j/bc8723/32.png) [@jlandwerlen](https://forum.inductiveautomation.com/u/jlandwerlen)\
**Post date:** [July 2, 2021, 4:39pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/2 "2021-07-02T16:39:57Z")

</div>

Welcome to the forum.

This should help you, [system.tag.browse - Ignition User Manual 8.1 - Ignition Documentation](https://docs.inductiveautomation.com/display/DOC81/system.tag.browse)

---

<div class="post-metadata">

**Author:** ![theo](https://avatars.discourse-cdn.com/v4/letter/t/a87d85/32.png) [@theo](https://forum.inductiveautomation.com/u/theo)\
**Post date:** [July 5, 2021, 1:35pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/3 "2021-07-05T13:35:50Z")

</div>

Hello!

Thank you for your answer.

I found that function and tried to use it but maybe it's not the right place or i executed it badly but it doesnt work

> system.tag.browse('[default]',{"recursive":True})  
> for result in results.getResults():  
> print result

Should I put it in a 'For' loop ? Does it have to be used inside a script or in an expression ?

Do you have any example ?

Théo.

---

<div class="post-metadata">

**Author:** ![cmallonee](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmallonee/32/6416_2.png) [@cmallonee](https://forum.inductiveautomation.com/u/cmallonee)\
**Post date:** [July 5, 2021, 3:18pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/4 "2021-07-05T15:18:30Z")

</div>

You don’t seem to be storing the returned value from the function in a variable. Also - and this could just be a formatting issue - your print statement must be indented. I’m surprised this code is not throwing an error/exception when you try to execute it; I would expect a `NameError` since `results` does not exist as a variable by the time you reference it.

Try this:

```auto
results = system.tag.browse(’[default]’,{“recursive”:True})
for result in results.getResults():
    print result

```

---

<div class="post-metadata">

**Author:** ![andrewk](https://avatars.discourse-cdn.com/v4/letter/a/bb73d2/32.png) [@andrewk](https://forum.inductiveautomation.com/u/andrewk)\
**Post date:** [October 31, 2022, 3:33pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/5 "2022-10-31T15:33:49Z")

</div>

Following up on this. Should this be applied with an expression binding to the options object? Getting errors when trying to populate the list.

Thanks

---

<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:** [October 31, 2022, 3:43pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/6 "2022-10-31T15:43:39Z")

</div>

> [@andrewk](#):
>
> expression binding

This is a script, not an expression.

To populate a dropdown from a tag browse, I would not expect there to be any binding at all, rather, on some type of event run this script and write the list to the options object at that time.

I suppose you could use a binding to some dummy value and then use a script transform to run the script.

The provided script does not build the required dictionary structure that the options property expects, so there will need to be some additional code.

---

<div class="post-metadata">

**Author:** ![andrewk](https://avatars.discourse-cdn.com/v4/letter/a/bb73d2/32.png) [@andrewk](https://forum.inductiveautomation.com/u/andrewk)\
**Post date:** [October 31, 2022, 4:44pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/7 "2022-10-31T16:44:26Z")

</div>

Approaching it from the project library scripts, could you tell me what I'm missing?

```auto
def tagNames():
	results = system.tag.browse(path = "[default]_AlignmentPress1/MOD0_GEN/CycleTime")
	for result in results.getResults():
	    tagPath = str(result['fullPath'])
	    tagName = tagPath.replace("[default]_AlignmentPress1/MOD0_GEN/CycleTime/","")
	    print tagName

def tagPaths():
	results = system.tag.browse(path = "[default]_AlignmentPress1/MOD0_GEN/CycleTime")
	for result in results.getResults():
		tagPath = str(result['fullPath'])
		tagName = tagPath.replace("[default]_AlignmentPress1/MOD0_GEN/CycleTime/","")
		print tagPath

```

Would I need to create a method that writes to "value" and "label" for the options object?

---

<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:** [October 31, 2022, 5:21pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/8 "2022-10-31T17:21:22Z")

</div>

Yes

Rather than printing the tag name, you need to construce a `List` of `Dictionary` objects.

The value is how you determine what has been selected, often this is some type of index value, though it can be anything. Label is what the end user will actually see in the dropdown list.

I would do something like this:

```auto
def tagNames():
	parentPath = "[default]_AlignmentPress1/MOD0_GEN/CycleTime"
	results = system.tag.browse(path = parentPath)
	return [{'value':idx, 'label':tagPath.replace(parentPath,'')} for idx, result in enumerate(results.getResults())]

```

You can set the value to the full tag path, or you could use a call to readBlocking to get the actual value of the tag, or you could set the value and the label to the same thing. Just depends on how you plan to use the drop down.

Since this is in a script library, it is possible to use an expression binding with the `runScript` expression function, to run it.

---

<div class="post-metadata">

**Author:** ![andrewk](https://avatars.discourse-cdn.com/v4/letter/a/bb73d2/32.png) [@andrewk](https://forum.inductiveautomation.com/u/andrewk)\
**Post date:** [November 1, 2022, 1:34pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/9 "2022-11-01T13:34:18Z")

</div>

Super helpful, and appears to have solved the issue. Thank you

---

<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:** [November 1, 2022, 2:02pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/10 "2022-11-01T14:02:09Z")

</div>

> [@andrewk](#):
>
> ... appears to have solved the issue.

Don't forget to hit the "Solution" link on the answer that worked!

---

<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:** [November 1, 2022, 2:10pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/11 "2022-11-01T14:10:21Z")

</div>

Don't think that @andrewk is the OP.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 5, 2023, 1:38pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/12 "2023-05-05T13:38:27Z")

</div>

I just did this and found a rather simple solution (for my use case). Can easily be adapted as needed.

I made an expression memory tag and used the `runScript()` function to fill a dataset with the description and name (parameters from my UDT). Then, a binding with a script transform on the options prop. This method is great because it will automatically add new objects to the dataset for use in the dropdown.

Get the list of all sensors in my "Analog\_Sensors" folder:

```auto
def getSensorList():
	#get all tags in the analog folder
	tags2 = system.tag.browseTags(parentPath = "[default]Analog_Sensors",udtParentType="Scaled_Analog_2SP")
	tags4 = system.tag.browseTags(parentPath = "[default]Analog_Sensors",udtParentType="Scaled_Analog_4SP")
	
	tags = tags2 + tags4
	
	#extract tag names and descriptions
	names = [str(t.name) for t in tags]
	desc = [str(d.value) for d in system.tag.readBlocking([str(t)+"/Parameters.Name_SA2SP" for t in tags]) ]
	
	#create dataset
	headers = ["Description", "Tag Name"]
	data = [[desc,name] for desc, name in zip(desc, names)]
	
	#print data
	
	dataset = system.dataset.toDataSet(headers, data)
	
	return dataset

```

Tag list dataset tag:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/5/750c0be481b3cfab0334a61c9185b51e3645ddf7.png)

Binding to the options array:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/6/b62170d3748bf30fbeb5fc8158fad83a2c70ab75.png)

```auto
def transform(self, value, quality, timestamp):
	options = []
	
	data = system.dataset.toPyDataSet(value)
	
	for row in data:
		desc = row["Description"]
		name = row["Tag Name"]
		options.append({"label":desc+" ("+name+")","tag":name})
		
	sortedData = sorted(options, key=lambda d: d[self.custom.sort_by])
	
	return [dict(item, **{'value':index}) for index, item in enumerate(sortedData)]

```

\*\*`self.custom.sort_by` is an extra parameter that I used to allow users to change the sort order when they're looking at the list - sorting is an entirely optional step, just substitute `options` for `sortedData` in the return statement if you don't want to do any sorting.  
(I also wanted buttons for advancing to the next and previous items in the list, so knowing the currently selected index was important - that's the reason that `value` is always equal to the index, it avoids having to search through the options list to find the value that matches the current selection.)

Then, just add one extra prop to the dropdown, and this prop can be used for indirect bindings.

```auto
selectedTag = {this.props.options}[{this.props.value}]["tag"]

```

@theo @andrewk

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [May 5, 2023, 3:07pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/13 "2023-05-05T15:07:38Z")

</div>

> [@amarks](#):
>
> ```auto
> tags2 = system.tag.browseTags(parentPath = "[default]Analog_Sensors",udtParentType="Scaled_Analog_2SP")
> tags4 = system.tag.browseTags(parentPath = "[default]Analog_Sensors",udtParentType="Scaled_Analog_4SP")
> 	
> tags = tags2 + tags4
> 
> ```

You can do this instead:

```python
tags = system.tag.browseTags(
    parentPath="[default]Analog_Sensors",
    udtParentType="Scaled_Analog_*SP"
)

```

edit: I'm confused.  
how does that even work ?

```auto
names = [str(t.name) for t in tags]
desc = [str(d.value) for d in system.tag.readBlocking([str(t)+"/Parameters.Name_SA2SP" for t in tags]) ]

```

- browse results don't have a `.name` property, only a `['name']` attribute.
- casting a browse result into a string does not look like a path at all.

Is there another step I missed ?

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 5, 2023, 3:43pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/14 "2023-05-05T15:43:03Z")

</div>

> [@pascal.fragnoud](#):
>
> You can do this instead:
> 
> ```python
> tags = system.tag.browseTags(
> parentPath="[default]Analog_Sensors",
> udtParentType="Scaled_Analog_*SP"
> )
> 
> ```

Good catch. \*\*edit: changing that results in an error because that parameter does not support wildcards. I think I did actually try that first.

```auto
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<module:Lists>", line 7, in getSensorList
ValueError: tagPaths list should not be empty

```

> [@pascal.fragnoud](#):
>
> edit: I'm confused.  
> how does that even work ?
> 
> ```auto
> names = [str(t.name) for t in tags]
> desc = [str(d.value) for d in system.tag.readBlocking([str(t)+"/Parameters.Name_SA2SP" for t in tags]) ]
> 
> ```
> 
> - browse results don't have a `.name` property, only a `['name']` attribute.
> - casting a browse result into a string does not look like a path at all.
> 
> Is there another step I missed ?

`browse` is different than `browseTags`

.name is the literal name of the tag.

See the [example](https://docs.inductiveautomation.com/display/DOC/system.tag.browseTags) in the manual.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/d/cd33551b0d320b390d40a2b92e4746c74bfb0b67.png)

Does `system.tag.browse()` work to filter on UDT type?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 5, 2023, 3:57pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/15 "2023-05-05T15:57:02Z")

</div>

You all might find the `jsonValues` virtual property interesting. As in, `system.tag.readBlocking(["path/to/folderTag.jsonValues"])`. It returns a JSON structure describing all the tags in the folder.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 5, 2023, 4:09pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/16 "2023-05-05T16:09:05Z")

</div>

> [@amarks](#):
>
> Does `system.tag.browse()` work to filter on UDT type?

To answer my own question, yes you can filter on UDT type using `typeId`, but it also does not support the wildcard character.

> [@paul-griffith](#):
>
> `system.tag.readBlocking(["path/to/folderTag.jsonValues"])`.

I've not messed with JSON structures much, but I can see how that would be useful. That's alot of information to parse out all at once and my solution is working, so I it's just not something I'm willing to put time in to at the moment.

I also like that my solution is fairy straightforward and someone who's not me _should_ be able to follow it in the future. Not everybody I work with is a text programmer (lots of ladder around here), so nested loops to parse out the JSON might cause more issues.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 5, 2023, 4:10pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/17 "2023-05-05T16:10:30Z")

</div>

Is there a reason that `browseTags()` still directs to the 7.8 manual? - It also doesn't show up in the script auto-complete menu either.  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/0/0/00633bb1f84cdd50f7f222c676d7b1685c86ff53.png)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 5, 2023, 4:11pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/18 "2023-05-05T16:11:48Z")

</div>

browseTags is deprecated. Browse is the modern replacement.

---

<div class="post-metadata">

**Author:** ![amarks](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/amarks/32/45610_2.png) [@amarks](https://forum.inductiveautomation.com/u/amarks)\
**Post date:** [May 5, 2023, 4:13pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/19 "2023-05-05T16:13:01Z")

</div>

Is there any real reason that I should switch over to `browse()` instead of `browseTags()`, considering that it's working and complete at the moment?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 5, 2023, 4:16pm UTC](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457/20 "2023-05-05T16:16:28Z")

</div>

Getting links to it in the modern manual?

Basically... no, probably not. With pretty much only one exception I can think of, we never remove scripting functions and take great pains to make 'legacy' functions continue to work after an upgrade. It is _possible_ we change that policy at some point in the future, so across a major version change (ex 8.3 -\> 8.4/5) you'd have to change your scripts to the modern alternative function, but I would not consider it _likely_ to happen. `system.tag.browseTags` _is_ already gone from the autocomplete in the software, which is another consideration w.r.t maintenance.

[Next page](https://forum.inductiveautomation.com/t/fill-dropdown-list-with-folder-of-tags/48457.md?page=2)
