# Tab Strip Scripting and Binding

**URL:** <https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600>\
**Category:** Ignition\
**Created:** [October 12, 2020, 5:30pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600 "2020-10-12T17:30:23Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 12, 2020, 5:30pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/1 "2020-10-12T17:30:23Z")

</div>

Hi all,

I am new to Ignition and scripting (and everything else). I am adding a Tab Strip to the project I am using to learn.

I have the Tab Strip bound to a Named Query that returns 2 columns. An id and a name.

Based on what I have read, it looks like scripting is pretty much limited to an event script. If there is a better way, please let me know.

I want to be able to do the following:

1. Set the Tab names to the names in the names column of the query.

2. Pass the id to a parameter or a value.

Is binding this to the query the right way to do this? The query dataset will be dynamic and I will want the Tab Strip to adjust accordingly.

I have read through a lot of previous post but I think many of them are beyond my current understanding.

What I do not see is a property for each tab to be able to see the names.

Any direction you can provide will be much appreciated.

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [October 12, 2020, 5:41pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/2 "2020-10-12T17:41:24Z")

</div>

The ignition programming setup is event driven programming, you are correct on that. You only call scripts on events, whether the event is a tag change, a GUI interaction, or something else that is changing or causing an event.

If you make a fresh Tab Strip component, then click on the Tab Data to see what is currently there, you’ll see this

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/3/9/3977532f430bb0e9efc2f89d8106db6063224cfa.png)

These are the columns you need to alias in your SQL `SELECT` clause which you’ll need bounnd to the Tab Data component.

Yes, binding to a SQL query I believe is the way for you to do this especially if you want it dynamic as you can set a SQL polling rate in the situation where you might have users manually changing items in the database that will change the tab appearance.

The important bit here is this - you need to `SELECT something as tabPropertyName` in your query. So just for the names of the queries you would need to do `SELECT myDBColumn as NAME, otherDBColumn as DISPLAY_NAME, ...` and in this instance, whatever your otherDBColumn value is is what the Tab will display. The NAME property I believe is used for the selected tab property on the tab strip.

Ignition offers a really good intro course I highly recommend going through either as needed or all at once if you have the time - [Browse the Lesson Library at Inductive University](https://www.inductiveuniversity.com/courses/whats-new-in-ignition-8/8.0)

Also, their documentation is normally very good and has pages on their scripts as well as components.

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 12, 2020, 5:58pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/3 "2020-10-12T17:58:59Z")

</div>

@bkarabinchak.psi,

I never thought about it like that. So I can use event.source.tabData as the source table (or dataset in this case) in the query?

I will try to put this together and see what happens.

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [October 12, 2020, 6:17pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/4 "2020-10-12T18:17:54Z")

</div>

Maybe I misunderstood.

What I am saying is that for your Tab Data property, it makes sense to bind it to a SQL query if you are basing it on a database table.

So you would bind Tab Data to a SQL Query Binding (or Named Query Binding if you already have one), but the important thing is that in your SQL Query or Named query, the columns you select MUST line up with the `NAME`, `DISPLAY_NAME`, `ENABLED`, etc, if you want the results of the query to affect the Tab Strip appearance. You can select additional columns but they won’t affect the Tab Strip appearance.

If your tabs are going to be static, you can also always right click on the tab strip -\> customizers -\> Tab Customizer, and then enter your tab strip information manually. In fact, perhaps do this for just a few of the tabs you are expecting, and then take a look at the Tab Data property data to see how it affects the columns. It might help illuminate things for you.

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 12, 2020, 7:16pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/5 "2020-10-12T19:16:25Z")

</div>

@bkarabinchak.psi,

I’m sorry, but I don’t understand. How do I get the dataset into a query?

I have a table (binder\_topics) with 2 columns: id, topic\_name. I want to use the topic\_name in my dbtable as the Display\_Name in the Tab Strip dataset.

Sorry but all this is very new to me.

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 12, 2020, 7:20pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/6 "2020-10-12T19:20:57Z")

</div>

I think we need to start at the beginning. I have a meeting in about two minutes, but I can maybe help answer afterwards.

Is this going to the same named query, and just changing parameters?

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 12, 2020, 7:33pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/7 "2020-10-12T19:33:05Z")

</div>

@JordanCClark

> [@JordanCClark](#):
>
> Is this going to the same named query, and just changing parameters?

I don't think so. I want be able to change the names on the tabs and output a value (which I dont think is an issue).

I am reading up on changing datasets now.

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 12, 2020, 8:35pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/8 "2020-10-12T20:35:52Z")

</div>

@JordanCClark @bkarabinchak.psi,

So looking at Datasets, I cam up with this…

newData = system.dataset.setValue(event.source.tabData, 0, 1, “newName”)  
event.source.tabData = newData

I put this in the property change event on the Tab Strip. It does change the name of the Display Name of row 0 and the remainder of the dataset remains the same. HOWEVER, Ignition Designer comes to a screeching halt and the Console window freezes up.

So something I am doing is not liked.

Thanks, Steven

---

<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:** [October 12, 2020, 8:41pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/9 "2020-10-12T20:41:35Z")

</div>

Your property change event is firing itself, repeatedly; that’s what’s causing the lockup. Introduce a custom property running the query, and filter the property change event to that property’s name.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 12, 2020, 8:59pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/10 "2020-10-12T20:59:24Z")

</div>

put the query in a custom property. Then in the propertyChange event:

```python
if event.propertyName = 'whatever_you _call_your_custom_property':
    do_some_stuff

```

Looking for a specific property name will help you filter out unwanted events.

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 12, 2020, 9:25pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/11 "2020-10-12T21:25:49Z")

</div>

@paul-griffith & @JordanCClark

Ok, so something like this?

In Custom Methods I can run the query to get the id and names.

topic\_list = system.db.runNamedQuery(“topic\_list”)

The in the property change, I can do this…

if event.propertyName = ‘topic\_list’:  
here I will modify the dataset and replace it.

so doing this, the property change will fire everytime the query is run, or changes?

I sure appreciate all the help!!

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 13, 2020, 3:42pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/12 "2020-10-13T15:42:56Z")

</div>

Hi Steven, sorry for the late reply. The needs of production outweigh the needs of the forum. Or something like that.

I’m getting something written up for you. Still be a few minutes. 🙂

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 13, 2020, 3:44pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/13 "2020-10-13T15:44:31Z")

</div>

@JordanCClark,

I guess I do not grasp the concept. I can capture the ‘selectedTab’ property in an if statement and can print the selected tab and the dataset each time the selectedTab changes.

But when I change the dataset in the if statement, it goes into the perpetual loop and freezes.

Just saw your message and I totally understand. Work always comes first and I would expect nothing less. Gives me lots of time to read and try stuff… 🤣 🤣 🤣

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 13, 2020, 4:01pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/14 "2020-10-13T16:01:28Z")

</div>

Ok here is something for you to play with. Import this into a fresh project so it doesn’t interfere with anything you have now.

[JC\_TabStrip\_From\_Query\_2020-10-13\_1145.zip](https://forum.inductiveautomation.com/uploads/short-url/4JN75MYPI80Hrsv90hlwxVHfnOc.zip) (6.6 KB)

I added two custom properties to the tab strip.  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/4/f/4f48f81785438769fd41cd89e483e70ca41bef63.png)  
_topic\_list_ is bound to the named query, also named _topic\_list_

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/f/cf06069feaa2ed91560d978237068b7669f7e1e9.png)  
_tabFormat_, I just copied from the default tabData, and deleted all but one row. We’ll use this in a bit to craete the new tabData.  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/2/d22fccc8707088ee0c60f811e0906b6023f7d3ca.png)

In the propertyChange event:

```python
if event.propertyName == 'topic_list':
	# Get the tabstrip component. Since we will be referencing
	# it a lot, it's handy to create an easy reference.
	tabStrip = event.source
	# Get the PyDataSet version of topic_list
	topicDataSet = system.dataset.toPyDataSet(tabStrip.topic_list)
	# Get the pyDataSet version of the tab format
	formatDataSet = system.dataset.toPyDataSet(tabStrip.tabFormat)

	# Create format list. It's just everything after the
	# tab name and display name. This will get added to the id 
	# and topic from the topic list dataset 
	format = list(formatDataSet[0])[2:]

	# Get the tabData headers. It's why I kept all the columns
	# in for format dataset.	
	tabDataHeaders = list(formatDataSet.getColumnNames())
	dataOut = []

	# Iterate through the topics and add the format to it.
	for row in topicDataSet:
		dataOut.append(list(row) + format)
	
	# Write the new tabData
	tabStrip.tabData = system.dataset.toDataSet(tabDataHeaders, dataOut)

```

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 13, 2020, 5:31pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/15 "2020-10-13T17:31:38Z")

</div>

@JordanCClark,

This is exactly the function I wanted. Now I understand the custom property. Each time the topic\_list changes (or is opened and closed) it is seen as a property change and fires the event.

I know what is happening below, but do not understand how.

> [@JordanCClark](#):
>
> # Create format list. It's just everything after the # tab name and display name. This will get added to the id # and topic from the topic list dataset format = list(formatDataSet[0])[2:] # Get the tabData headers. It's why I kept all the columns # in for format dataset. tabDataHeaders = list(formatDataSet.getColumnNames()) dataOut =

Where can I get more details on the list() function. The manual shows list but nothing this detailed.

Thanks so much!!!

Steven

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 13, 2020, 5:33pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/16 "2020-10-13T17:33:16Z")

</div>

> [@steven.cox](#):
>
> Where can I get more details on the list() function.

This should be an okay start on python collections.

> **[Python Lists](https://www.w3schools.com/python/python_lists.asp)**
>
> W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 13, 2020, 7:25pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/17 "2020-10-13T19:25:26Z")

</div>

@JordanCClark,

ok, so we are making a list starting at index 2. However, what is the [0] for? I am assuming it is row 0 of formatDataSet. I did not see that in the Python tutorial or the Ignition manual.

> [@JordanCClark](#):
>
> format = list(formatDataSet[0])[2:]

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 13, 2020, 8:41pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/18 "2020-10-13T20:41:17Z")

</div>

> [@steven.cox](#):
>
> I am assuming it is row 0 of formatDataSet.

You are correct, sir!

> [@steven.cox](#):
>
> I did not see that in the Python tutorial or the Ignition manual.

This actually digs a bit deeper into the java classes for datasets and pyDataSets, but the upshot is that pyDataSets can use subscripts and make lists out of the rows, while normal (for lack of a better word) datasets cannot. For me, it's a matter of convenience. You could do the same thing without making it a pyDataSet and using a loop or list comprehension:

```python
formatDataSet = tabStrip.tabFormat
format = [dataset.getValueAt(0,i) for i in range(2,formatDataSet.getColumnCount())]

```

-or-

```python
formatDataSet = tabStrip.tabFormat
format=[]
for i in range(2,formatDataSet.getColumnCount()):
	format.append(dataset.getValueAt(0,i))

```

Personally, I prefer the subscripts as it's easier for me to read. More of a style preference, really, as each dataset type has its own set of useful features.

Hopefully, I didn't throw more mud in the water for you.

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 13, 2020, 9:58pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/19 "2020-10-13T21:58:47Z")

</div>

> [@JordanCClark](#):
>
> Hopefully, I didn’t throw more mud in the water for you.

No Sir that is great!! I will work this into my project.

Again, thanks so much for the help and the resources.

Thanks, Steven

---

<div class="post-metadata">

**Author:** ![steven.cox](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/steven.cox/32/18589_2.png) [@steven.cox](https://forum.inductiveautomation.com/u/steven.cox)\
**Post date:** [October 15, 2020, 6:01pm UTC](https://forum.inductiveautomation.com/t/tab-strip-scripting-and-binding/39600/20 "2020-10-15T18:01:15Z")

</div>

@JordanCClark so I ran into a problem when implementing the tab strip into my project.

The Selected Value of the tabstrip is a string. The query in my table expects an integer. As built, the Selected Value of the tab is actually a number because we use the topic.id(index) of the topic\_name.

But because the datatype was a mismatch it would not work.

SO, I created another custom property on the tabstrip, named it selectedTabInt. I then added an expression to selectedTabInt using toInt({Root Container.Topic Tab Strip.selectedTab}, -1).

I then used selectedTabInt as the parameter in the query. Works great.

Thanks for the lesson!!

Steven
