Nested Action Loops

I built this functionality today for a client, it seemed very share-worthy, especially since I wasn’t quite sure it would work until after I built it.

There have been many posts about how to setup looping actions and how to automatically generate a number of new records. If you haven’t read those threads, you should start with those before reading this one. I may or may not come back to edit this post to link some of those other threads. Well here is one at least, since the community is trying to tell me my “topic is similar to…” :

This is an even more advanced setup, where there is a loop within a loop.

The functionality is built to allow employees to request certain shifts across certain dates. We wanted the app users to be able to quickly select multiple shifts and multiple dates, so I setup two EnumLists for them to select multiple from, inside a single record.

Column structure for **shift_request_input** Table

HOWEVER
For the schedulers to do their job, and be assisted by some app automation, it is much easier/better to see individual records linking each single shift to each single date. So what I wanted to do here is to create all combinations of shifts versus dates from these two EnumLists.

As you can hopefully already tell, we can’t just loop across one EnumList and create the records, we need to have an inner loop to loop across the 2nd EnumList within the loop for the first EnumList.

The general overview strategy here is:

1. Outer loop
  A. Re-calculate COUNT for inner loop
  B. Execute inner loop
    i.Inner loop
      a. Create a new record
      b. Decrement inner loop count
      c. Re-loop inner loop (IF count > 0 )
  C. Decrement outer loop count
  D. Re-loop outer loop (IF count > 0 )

And here is a general overview screenshot of the set of actions:

*Extra bonus tip here too, you get to see the naming schema that I use when creating large grouped action sets.*

Action Set Overview.


And here are the individual Action Definitions.
GROUP 7 | outer group , loop over dates

3X_6_7_671bbe648fc7ceaaaa1b3d997f37f37bd797fb77.png

GROUP 7-1 | reset shift_count

3X_3_9_3916f740c96bfaa96cb6d8f4251579ceea72ebf3.png

GROUP 7-2 | execute inner group

3X_7_a_7a13dc7f59d3db369f4e15a196d81d41db6d805e.png

GROUP 7-2-1 | inner group , loop over shifts

3X_f_6_f6641e9b6c9fd5a6b2655113b3ba4ac97942747d.png

GROUP 7-2-1-1 | create new shift_request

3X_6_7_67db7f4039ddfa6e7565d2b305e824e40c9f0508.png
You can see 90% of the expressions there, but they are simply:
INDEX( [enumlist] , [enumlist_count] )

GROUP 7-2-1-2 | decrement shift_count

3X_4_4_44ecd1b1889e94537b943642362ab86af9ffc05f.png

GROUP 7-2-1-3 | re-loop inner group

GROUP 7-3 | decrement date_count

3X_9_f_9f398436b369677b5a76bb072ed1e254b3f9c1dd.png

GROUP 7-4 | re-loop outer group

This entire Action group is set as the Form Saved Behavior for the shift_request_input Form view. I might move it to be executed via Bot so that the users don’t have to potentially sync dozens of records on their end, but I haven’t gotten that far yet.

* [employee_month] is just a Ref column to a parent record. *

12 15 1,828
15 REPLIES 15

This IS absolutely share-worthy

Nice one! 3X_c_8_c894633685b607dcad8bd19f28d5c98f0a09a31f.gif


Only hiccup I see is this:

  • This unfortunately doesn’t work.
    • Bots can’t run through loops - at the moment at least.

There used to be a loop depth limit listed in the limitations documentation, but it’s not listed anymore (probly since bot-loops don’t work at the moment).

This is kind of old but this can be done with a bot as of late! Just wanted to update it since it is the top reply

Ami
Bronze 5
Bronze 5

Hi
What is the end result for the user? I understand the looping, i use it myself, but can’t visualise the purpose, thanks in advance

There are 2 different types of users here: “requesters” and “schedulers”

This is the preferred/easiest way for the requesters to enter their shift requests. Here it is just a single record, but it indicates 4 shift requests.

3X_2_8_28ee2b316ec7907764883a093fa77eaf9dab10fa.png

The purpose of the nested loop is to split this single record into 4 separate records, the 4 possible combinations (2 x 2), which is the preferred form for the records to be in to be used by the schedulers. These 4 records would look like this:

3X_f_e_fe09881caf22350abdc0e455e7d3c080f2308f80.png


A single loop could only handle the case where you’d have one List type column. You need another nested loop for every additional List type column that you want this sort of functionality to act on.

Wow! I have looked for something like that for a while, i built a routing app and needed all possible combinations of locations, ended up doing it with excel. This may be the solution.

To answer your question from a user experience point of view, one advantage with the looping construct @Marc_Dillon has highlighted, you can provide a quicker way for the users to select a list of items that are normally recorded as child rows. Adding each child row one by one, especially when there are several, is extremely monotonous and slow - i.e. inefficient.

For example, in an Ordering process, you could provide the user with a dropdown list of products that they can select multiple items from (an EnumList column). When they Save, you can use the looping pattern to automatically add the child Order Detail rows to the Order. You can then finish by presenting that list of Order Detail rows in an editable table where the user can simply go down the table rows and adjust the Quantities (as well as other details) of each ordered product in a single view.

Another example might be assigning a list of programs or services to a client. Instead of adding one-by-one use the EnumList approach above.

There are many other use cases for this looping construct but the main idea in all of them is to give the user a quick and easy way to select the items they want/need and let the system do the majority of the work.

Hi,

First of all thank you very much for posting this solution. I have been grinding my head gears for a while trying to nest some actions. Basically i have the following situation :

  • Product Table
  • Product Variation Table

Product Table holds a few enumlists for Attributes like Shape, Colour, Feet, Feet Colour, etc.
Product Variation Table has columns of type ref in which you can only select one of the referenced attributes in the according attributes list.
I am trying to create all possible combination of attributes. I took inspiration from your solution but changed a few things :

  • The loop tracking column is named Shapes_List and instead of using Count(Products[Shapes]) to keep track of loop i am using the actual values from Products[Shapes] and i am updating it with the following formula : Products[Shapes]-LIST(INDEX(Products[Shapes],1))

  • Because of the previous situation all the columns that get added by the inner loop action have the following formula : INDEX(Products[Shapes],1)

    I currently have on extra layer nested compared to your solution but will need to increase it to 7 deep. As it stands when i press the action button the app freezes and does not respond. From my calculations the resulting rows would be upwards of 1500.
    Is this too much for the app to handle ? Should i leave it non responding for a longer period of time, maybe it will finally generate them ? Are there any problems to the way im keeping track of the loop and could that be the reason for the app freezing ?

Yikes. I’ve set up a looping record creation on an app that goes up to about 100 syncs at once, and that’s already a bit too much. 1500 syncs at once is not a sustainable solution. If this is just something you only need to do like once, I would just do it directly in your backend GSheet or something. Check out this article for possible inspiration in that regards.

May I ask why you are trying to generate all possible combinations?

I ask, because I wonder if there might be a more efficient way. Remember, all those rows will need to be maintained with updates over time.

As an example, I built an app where initially the thought was to create Product rows for each combination of options for the manufactured item to assign Pricing. It would have been over 800 rows. The problem would be when it is time to update the pricing for all of them. Say a particular Color becomes scarce and cost of a color pigment increases. Finding and Updating all rows with that color one by one would be a nightmare.

It occurred to us that the price increase would likely be equal so we could automate the update to all the rows. But if that’s the case, then we could also strip out the option, price it on its own and then simply chose the options at Order time and calculate the price.

We ended up with a Base Product table and a Option Pricing table. A base price is assigned to the base product. Each option would have its own additive price. When an order is placed, the Base Product is chosen, all options selected and the Order Form calculates the Price on the fly.

The result was we reduced 800+ Pricing rows down to 60+ with Base and Option price items combined. Much more manageable!!!

That`s correct, this would be a one time thing for every supplier. I looked over the sheets formula but found it easier and faster with python. Its actually funny considering that for a 3 row deep cartesian join i had to create 15 individual actions and nest them accordingly with Python I was actually able to pull it off with 3 lines of code

list1 = [a+str(",")+str(b)+str(",")+str(c)+str(",")+str(d)+str(",")+str(e)
for a in SKUSTD for b in BodyMaterials for c in FeetType for d in FeetColour for e in Cover2]

list2 = [a+str(",")+str(b)+str(",")+str(c)+str(",")+str(d)+str(",")+str(e)+str(",")+str(f)
for a in SKUSCT for b in BodyMaterials for c in FeetType for d in FeetColour for e in Cover2 for f in Cover3]

list3 = list1 + list2

Turns out that COUNT(list3) = 8443080 and that`s for only one product and i have 20 more !

Thank you for your input, this is actually a great ideea and i think its the only way i can go about doing this. Haven`t given it too much thought but how would you keep track of current stock variation options ?

@Marc_Dillon , hi.

I couldn't find how to count [date_count] at Action Set Overview. Could you show me how to count the date_count?

Thank you.


@leinharte wrote:

how to count [date_count]


I'm not sure what you mean.

 

@Marc_Dillon 

I can't find the step for counting the "date_count".

leinharte_0-1699201468600.png

At GROUP 7-1 | reset shift_count, we count the shift_count. Where do we count the "date_count"? I think that we need the initial number of the "date_count".

Thank you.

You can initialize the date_count with an Initial Value COUNT([date_enumlist])

@Marc_Dillon , Thanks for your answer.

I solved it like this. (Nested Grouped Actions)

I made another grouped action that had 2 sub-actions.
- sub-action1: COUNT([date_enumlist])
- sub-action2: execute GROUP7

Thank you.

Top Labels in this Space