Avoiding Power Automate Update Loops With Trigger Conditions

Blog

Avoiding Power Automate Update Loops With Trigger Conditions

I recently needed to write a Flow in Power Automate that automatically updated a list item on SharePoint when that item was updated with particular conditions. The problem is that when you automatically update the list item, it triggers the Flow to run again, which updates the list item, which triggers the flow again. You end up with a never ending loop. I’ll walk through the use case, and how I solved this.

Part of what I do as the Director of Creative Design Services is design, build, and manage all of our tracking systems. Everything is built in SharePoint, since that’s what the organization has invested in. This has bound me to learning SharePoint and Power Automate much more deeply than I had ever intended in my career. The more I learn about Power Automate and SharePoint, the more impressed I am. I’m also frustrated by some of the complexities of the system, but if you can learn to work with them, there are some fairly powerful things you can do by leveraging this enterprise system.

So we have several SharePoint lists. One list tracks the development of online courses. Two of these fields that are being tracked are “Development Status” (a drop down field, but not a lookup field) and “Development Completion Date” (a date formatted field). I needed to create a flow that checked whether the Development Status was marked as “Complete” and then update the Development Completion Date to today’s date.

So I started with creating an Automated cloud flow from blank. The flow’s trigger was “When an item or file is modified”. So when an item is modified in the SharePoint list, I want this flow to run.

I gave that trigger the Site Address and List Name.

What I wanted to do was to update a field within the item with today’s date when the item was marked as complete. So I first created an “Update Item” block, and passed the Site Address, List Name, and ID (from the “When an item or a file is modified” block.) Since I wanted to update the “Development Completion Date” with today’s date, I went to that field in the Update Item block, clicked on that field, then clicked on “Expression” in the content modal.

The Expression field is for writing expressions or code that you need to use. There are some built-in functions, so I used utcNow(), without any formatting (since the field is already formatted in the list. SharePoint took care of the formatting for me, I just needed to pass it the utcNow() value.)

As a side-note, any fields left blank will just retain the value that they already had. You may have dropdowns with default values, which you’ll see in your Update item block. You can either pass the values back into them using the Dynamic content selector, or you can just delete whatever content is in that field, leaving it blank. This will allow the content for each of those fields to be carried over from the “When an item or a file is modified” block, which will be dependent on the ID, which you’re passing at the top of the Update Item block.

So now you have your blocks set up. At this point if you save and run this flow, it will enter a never ending loop, because it’s updating the item when it’s updated. To stop this from happening, what you need is called a Trigger Condition.

Trigger Conditions are conditions written as expressions that have to return true in order for the trigger to actually fire and run the Flow. You get to these by clicking on the 3 dots on the upper right of the “When an item or file is modified” block, and then clicking on “Settings”.

At the bottom of the settings window, you’ll see “Trigger Conditions”. If you click the Add button, you’ll be able to add the conditions which have to return a true value in order for this trigger to run.

I’ll just show my trigger condition, and then explain it…

@equals(triggerOutputs()?['body/DevelopmentStatus/Value'],'Complete')  

So this is really just a simple expression. This expression simply returns true if the queried field equals a specified value. In this case, the information being queried is the Development Status field value in the body of the trigger output. The trigger output is the output from the block that is being run, which contains the information from the item that you’re altering.

If you were to save and run this right now, this flow would only run if the Development Status was set to Complete. But, if it’s set to complete, it still would run indefinitely, because it’s updating itself every time it updates.

Having a second field is a great way to stop the never ending update loop. A 2nd trigger condition can check for a value in a field, and if that value is there, it will run. Otherwise, it won’t fire. So, as a simple example you could have a text field in your SharePoint that says “runme” in it. This field acts as a flag. When the trigger conditions check for conditions to run, you’d have one that checks for the Development Status, and one that has to say “runme” (as a simple example.) It the field is blank, or says anything else, it won’t run. On the update, you would remove the “runme” content from the field, essentially stopping the flow from running more than once.

While that’s not very realistic or helpful, it does illustrate the conditions that we can start to work with. In my case, I have a date field that’s related to the Development Status field. I only need to update the date field and run this particular flow intended to update the date field if the development status equals “Complete” and the date field is empty. If the date field has data in it, then the Development Status should equal “Complete”.

So, I created a new trigger condition…

@empty(triggerBody()?['DevelopmentCompletedDate'])

This checks whether the Development Completed Date field is empty, and returns true if it is. Now, I have two conditions that have to be true in order for this flow to run.

This essentially solves the problem of the loop, but not necessarily the entire workflow. What if somebody comes back in and changes the status, or what if the status was selected by mistake? That’s easily solvable.

I just created another Flow that checked if the Development Status was anything except “Complete” and that the Development Completed Date had information in it. I did that with these two trigger conditions. They basically wrap the previous trigger conditions in “not” filters.

@not(equals(triggerOutputs()?['body/DevelopmentStatus/Value'],'Complete') )
@not(empty(triggerBody()?['DevelopmentCompletedDate']))

Now the flow will run if the current item is not “Complete” and if date field has anything in it. These are the conditions that return true if somebody selects a new status after the status was set to “Complete”.

In the Update Items block, I simply pass a null value through to the Development Completed Date field by using the Expression and typing “null” into that, which populates the field with the Expression for Null. This is different than just typing “null” in the field itself. You have to be sure to use the expression builder and pass null in through that.

So once this runs, the field combination becomes Development Status: anything except Complete, and the date field is empty. Since we don’t have a flow written for that specific combination, no flow is triggered. This is because we’re only triggering flows under very specific circumstances in these two cases.

Now, when somebody selects “Complete” from the Development Status field and the date field is empty, the date will be automatically updated to the current date. If somebody selects anything except “Complete”, and there is a date, the date will be removed.

If there’s already a date there, and somebody selects “Complete”, nothing will happen. This is because the expectation is that the date field would be empty is somebody chooses “Complete”. Otherwise, they’d just be choosing “Complete” from the field, even though the field is already set to “Complete”. We don’t have a flow to run for that circumstance, because we don’t need one.

If there’s no date there, and somebody chooses any Development Status that’s not “Complete”, nothing will happen. This is because we don’t need to update the Completion Date field if it’s not being marked as “Complete”. We don’t have a flow to run for that circumstance, because we don’t need one for this either.

These two flows working together effectively manage the date field. We have two flows that are only triggered under specific circumstances that only manage the related fields. The down side is that Flows do get a bit difficult to manage. I’m almost certain it would be better to organize the entire workflow with Child Flows and HTTP requests (having one parent flow for when this list is updated, and then running multiple child flows out of it, if it’s even possible to have trigger conditions within child flows), but for now, this effectively solved my problem.

I hope this helps somebody else who’s spending an entire day trying to figure this out for the first time.

Jarred Truschke