# Multiselection Drop down selector default value

**URL:** <https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301>\
**Category:** Ignition\
**Tags:** ignition81, perspective, scripting\
**Created:** [May 30, 2023, 2:43pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301 "2023-05-30T14:43:06Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alexandre\_Potvin](https://avatars.discourse-cdn.com/v4/letter/a/8491ac/32.png) [@Alexandre\_Potvin](https://forum.inductiveautomation.com/u/Alexandre_Potvin)\
**Post date:** [May 30, 2023, 2:43pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/1 "2023-05-30T14:43:06Z")

</div>

Hi

I am using multiselection for 8 value but the user does not need to fill all of them to save in the DB the problem is that when the selection is not complet the link does not esxist. In a previous test i was using label and it work well the issue now is i have around 150 value in total and creating 150 hidden label is probably not the best way to do it.

Exemple the multiselect can have up to 8 value but in this case user entered only 2.  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/4/9/49a4651e7073ba37591ebb74da785800fde60d14.png)

Then my script for my querry does not work because the link does not exist.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/1/113effe5b85591d826be27b604cd96a54be3c96a.png)

Also is there a way to set the maximum value to exemple 8 ?

Thank You

---

<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:** [May 30, 2023, 3:02pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/2 "2023-05-30T15:02:12Z")

</div>

First off, having a hard-coded number of params is a questionable way to do this. Secondly, what value do you expect these params to have when not supplied by a user? Additionally, why are you binding a driving value against the displayed text of another component? Always bind against the pure data, so use whatever value the Label is bound to instead of using the Label itself.

```auto
# This will default all of the "missing" params to `None`
selected_options = self.getSibling("DROP_ABS").props.value
abs_params = [None] * 8
params = {}
for i in range(len(selected_options)):
    abs_params[i] = selected_options[i]
for i in range(len(abs_params)):
    params["ABS_{0}".format(i + 1)] = abs_params[i] # i + 1 to account for 1-indexed param names
params["ShiftID"] = self.getSibling("LABEL_15").props.text

# and then your query

```

A better way would be to use a prepared query with some indeterminate number of param values, and then use a script like this:

```auto
select_options = 
query = "select * from MyTable where name in ({0}) and ShiftID=?".format(['?' for option in select_options])
system.db.runPrepUpdate(query=query, args=selected_options + [self.getSibling("LABEL_15").props.text], database="SomeDB")

```

---

<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:** [May 30, 2023, 3:04pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/3 "2023-05-30T15:04:47Z")

</div>

As for setting the maximum amount of options a user could select, you'd use the change script and check against the length of `currentValue.value`.

```auto
if currentValue and len(currentValue.value) > 8:
    # note that this doesn't stop a user from selecting a ninth value, but it immediately removes the ninth value after selection.
    self.props.value = previousValue.value

```

---

<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 30, 2023, 3:28pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/4 "2023-05-30T15:28:56Z")

</div>

`itertools` can help make this a bit more pythonic:

```python
from itertools import izip_longest as zipl

params = {
	"ABS_{}".format(i): opt
	for i, opt in zipl(xrange(1, 9), selected_options[:8], fillvalue=None)
}
params["ShiftID"] = self.getSibling("LABEL_15").props.text

```

---

<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:** [May 30, 2023, 3:32pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/5 "2023-05-30T15:32:10Z")

</div>

Much better, but I think this would still require a bit more to adjust from being 0-indexed to 1-indexed.

---

<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 30, 2023, 3:33pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/6 "2023-05-30T15:33:16Z")

</div>

oops, edited for 1-based indexing.  
I always forget those exist 😃

edit:  
but to be honest, we'd need to see what the query actually looks like to figure out the best way of doing this.

---

<div class="post-metadata">

**Author:** ![Alexandre\_Potvin](https://avatars.discourse-cdn.com/v4/letter/a/8491ac/32.png) [@Alexandre\_Potvin](https://forum.inductiveautomation.com/u/Alexandre_Potvin)\
**Post date:** [May 30, 2023, 4:12pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/7 "2023-05-30T16:12:12Z")

</div>

Hi work well only thing is that this creat me a error in the designer when i have a no value. Probably not a problem.

if currentValue and len(currentValue.value) \> 8:  
# note that this doesn't stop a user from selecting a ninth value, but it immediately removes the ninth value after selection.  
self.props.value = previousValue.value

I used your firts option as the second one look to be over my current skillset.

Here is the querry i just learned how to do querry probably not the best.

IF EXISTS (SELECT \* FROM Employe\_Machine WHERE ShiftID = :ShiftID)  
UPDATE Employe\_Machine  
SET ABS\_1 = :ABS\_1, ABS\_2 = :ABS\_2, ABS\_3 = :ABS\_3, ABS\_4 = :ABS\_4, ABS\_5 = :ABS\_5, ABS\_6 = :ABS\_6, ABS\_7 = :ABS\_7, ABS\_8 = :ABS\_8,  
AS01\_1 = :AS01\_1, AS01\_2 = :AS01\_2, AS01\_3 = :AS01\_3, AS01\_4 = :AS01\_4, MP05\_1 = :MP05\_1, MP05\_2 = :MP05\_2, MP05\_3 = :MP05\_3, MP05\_4 = :MP05\_4,  
MP09\_1 = :MP09\_1, MP09\_2 = :MP09\_2, MP09\_3 = :MP09\_3, MP09\_4 = :MP09\_4, MP10\_1 = :MP10\_1, MP10\_2 = :MP10\_2, MP10\_3 = :MP10\_3, MP10\_4 = :MP10\_4,  
MP14\_1 = :MP14\_1, MP14\_2 = :MP14\_2, MP14\_3 = :MP14\_3, MP14\_4 = :MP14\_4, MP15\_1 = :MP15\_1, MP15\_2 = :MP15\_2, MP15\_3 = :MP15\_3, MP15\_4 = :MP15\_4,  
MP16\_1 = :MP16\_1, MP16\_2 = :MP16\_2, MP16\_3 = :MP16\_3, MP16\_4 = :MP16\_4, MP17\_1 = :MP17\_1, MP17\_2 = :MP17\_2, MP17\_3 = :MP17\_3, MP17\_4 = :MP17\_4,  
MP18\_1 = :MP18\_1, MP18\_2 = :MP18\_2, MP18\_3 = :MP18\_3, MP18\_4 = :MP18\_4, MP19\_1 = :MP19\_1, MP19\_2 = :MP19\_2, MP19\_3 = :MP19\_3, MP19\_4 = :MP19\_4,  
MP20\_1 = :MP20\_1, MP20\_2 = :MP20\_2, MP20\_3 = :MP20\_3, MP20\_4 = :MP20\_4, MP21\_1 = :MP21\_1, MP21\_2 = :MP21\_2, MP21\_3 = :MP21\_3, MP21\_4 = :MP21\_4,  
MP22\_1 = :MP22\_1, MP22\_2 = :MP22\_2, MP22\_3 = :MP22\_3, MP22\_4 = :MP22\_4, MP23\_1 = :MP23\_1, MP23\_2 = :MP23\_2, MP23\_3 = :MP23\_3, MP23\_4 = :MP23\_4,  
MP24\_1 = :MP24\_1, MP24\_2 = :MP24\_2, MP24\_3 = :MP24\_3, MP24\_4 = :MP24\_4, Relais = :Relais  
WHERE ShiftID = :ShiftID  
ELSE  
INSERT INTO Employe\_Machine (ABS\_1, ABS\_2, ABS\_3, ABS\_4, ABS\_5, ABS\_6, ABS\_7, ABS\_8, AS01\_1, AS01\_2, AS01\_3, AS01\_4, MP05\_1, MP05\_2, MP05\_3, MP05\_4, MP09\_1, MP09\_2, MP09\_3, MP09\_4, MP10\_1, MP10\_2, MP10\_3, MP10\_4, MP14\_1, MP14\_2, MP14\_3, MP14\_4, MP15\_1, MP15\_2, MP15\_3, MP15\_4, MP16\_1, MP16\_2, MP16\_3, MP16\_4, MP17\_1, MP17\_2, MP17\_3, MP17\_4, MP18\_1, MP18\_2, MP18\_3, MP18\_4, MP19\_1, MP19\_2, MP19\_3, MP19\_4, MP20\_1, MP20\_2, MP20\_3, MP20\_4, MP21\_1, MP21\_2, MP21\_3, MP21\_4, MP22\_1, MP22\_2, MP22\_3, MP22\_4, MP23\_1, MP23\_2, MP23\_3, MP23\_4, MP24\_1, MP24\_2, MP24\_3, MP24\_4, ShiftID)  
VALUES (:ABS\_1, :ABS\_2, :ABS\_3, :ABS\_4, :ABS\_5, :ABS\_6, :ABS\_7, :ABS\_8, :AS01\_1, :AS01\_2, :AS01\_3, :AS01\_4, :MP05\_1, :MP05\_2, :MP05\_3, :MP05\_4, :MP09\_1, :MP09\_2, :MP09\_3, :MP09\_4, :MP10\_1, :MP10\_2, :MP10\_3, :MP10\_4, :MP14\_1, :MP14\_2, :MP14\_3, :MP14\_4, :MP15\_1, :MP15\_2, :MP15\_3, :MP15\_4, :MP16\_1, :MP16\_2, :MP16\_3, :MP16\_4, :MP17\_1, :MP17\_2, :MP17\_3, :MP17\_4, :MP18\_1, :MP18\_2, :MP18\_3, :MP18\_4, :MP19\_1, :MP19\_2, :MP19\_3, :MP19\_4, :MP20\_1, :MP20\_2, :MP20\_3, :MP20\_4, :MP21\_1, :MP21\_2, :MP21\_3, :MP21\_4, :MP22\_1, :MP22\_2, :MP22\_3, :MP22\_4, :MP23\_1, :MP23\_2, :MP23\_3, :MP23\_4, :MP24\_1, :MP24\_2, :MP24\_3, :MP24\_4, :ShiftID)

---

<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 30, 2023, 5:56pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/8 "2023-05-30T17:56:12Z")

</div>

Holy mother of sandwiches, that's one ugly query !

> [@Alexandre\_Potvin](#):
>
> I used your firts option as the second one look to be over my current skillset.

It's not that complicated. Let's take it step by step, I can also explain in french if some things are unclear.  
I'll simplify a few things that are not relevant to understand what's going on.

```python
from itertools import izip_longest

```

`zip` is a built-in function that takes lists, and produces tuples containing an element from each list.  
For example:

```python
a = ['a', 'b', 'c']
b = [1, 2, 3]
zip(a, b)

```

Will produce `[('a', 1), ('b', 2), ('c', 3)]`.  
The function name actually reflects quite well what it does, if you think about a zipper (fermeture éclair):  
The problem with `zip` in this case is that it stops as soon as the end of one of the lists is reached.  
So we use `izip_longest` instead, which will go to the end of the longest list, filling the missing values with the supplied `fillvalue` (or None by default).  
For example:

```python
a = ['a', 'b', 'c']
b = [1, 2, 3, 4, 5]
izip_longest(a, b, fillvalue='x')

```

will produce `[('a', 1), ('b', 2), ('c', 3), ('x', 4), ('x', 5)]`

Using this, it doesn't matter how many options were selected with the dropdown.

```python
results = [do_something(element) for element in iterable]

```

This is a list comprehension. It's basically a one-line loop.  
What it does here is take every element from `iterable`, pass it to `do_something`, and returns a list with all the results.  
It's equivalent to this:

```python
results = []
for element in iterable:
    results.append(do_something(element))

```

But we don't need a list, we need a dictionary. Good thing you use the same principle to build a dictionary:

```python
d = {key: value for key, value in iterable}

```

This is where `zip` comes in handy, as it produces tuples we can use to get our `key` and `value`.  
If you have a list with keys and a list with values, zipping them together allows us to use this syntax:

```python
d = {k: v for k, v in zip(keys, values)}

```

The exact same syntax works with `izip_longest`.

We have a our values list, it's the `selected_options`. But we don't have a keys list... we can generate it with a list comprehension:

```python
keys = ["ABS{}".format(i) for i in xrange(1, 9)]

```

`range(low, high)` will generate a list of integers between `low` included and `high` excluded,  
so `range(1, 9)` generates `[1, 2, 3, 4, 5, 6, 7, 8]`.  
We can use those values to format a string with `"ABS{}".format(n)`.  
`xrange` does the same thing as `range`, except it produces a generator instead of a list, but don't worry about this.

So, we could make a list of keys beforehand... or inline it in the dictionary comprehension:

```python
d = {
    "ABS{}".format(i): option
    for i, option in zip(xrange(1, 9), selected_options)
}

```

Putting things on different lines doesn't affect the outcome, it just makes things clearer.

We're almost there, we just need to replace `zip` with `izip_longest`, and add a `fillvalue` in case there are less than 8 options. If we don't provide one, it will use `None`, which is probably what we want here anyway... but for the sake of explicitness, we'll add it anyway.  
Then make sure we only use the first 8 options, which can be achieve with a simple slice: `iterable[start:end]` will cut the list and return the elements between `start` and `end`.  
We'll also alias `izip_longest` to `zipl` when importing it. It's not necessary, it's just a habit I have.  
Putting everything together:

```python
from itertools import izip_longest as zipl

params = {
	"ABS_{}".format(i): opt
	for i, opt in zipl(xrange(1, 9), selected_options[:8], fillvalue=None)
}

```

All that's left to do is add any extra key:value pair you need in the dictionary, and you're done.

See, nothing complicated here !

---

<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 30, 2023, 6:03pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/9 "2023-05-30T18:03:18Z")

</div>

> [@pascal.fragnoud](#):
>
> `from itertools import izip_longest as zipl`

Psssst! The built-in `map()` does this if you give it `None` as its first argument. That is, your

```auto
zipl(iterableA, iterableB, ....)

```

is the same as

```auto
map(None, iterableA, iterableB, ....)

```

Saves you an import and allows you to use a highly-optimized built-in.

---

<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 30, 2023, 6:33pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/10 "2023-05-30T18:33:20Z")

</div>

I don't see myself explaining this during code review :X  
Also, if you need a fill value different than `None`... It gets ugly.

---

<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 30, 2023, 6:36pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/11 "2023-05-30T18:36:25Z")

</div>

> [@pascal.fragnoud](#):
>
> if you need a fill value different

The `None` is not a fill value. It is a no-op transform function. You can give `map()` a function or lambda that does pretty much anything you want. But with a no-op, it is equivalent to `izip_longest`.

Learning `map()` is worth your time.

---

<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 30, 2023, 8:08pm UTC](https://forum.inductiveautomation.com/t/multiselection-drop-down-selector-default-value/74301/12 "2023-05-30T20:08:16Z")

</div>

No, I know `map` and how it works.  
But it DOES pad with `None`, and if you need something else as fill value, it gets ugly.
