Logic Flow Control: If, Switch, For Each, and Assign
Key Takeaways
- The If node evaluates a boolean condition and routes execution down one of two paths (True or False); it is the workhorse for binary conditional branching in both Client and Server Actions.
- The Switch node evaluates a single expression and routes to one of several labeled branches based on its value — purpose-built for status-code or enum-style routing where one expression takes discrete known values.
- The For Each node iterates over a Record List, executing the body once per record; placing a Server Action call inside a For Each causes the N+1 query problem and should be refactored to pass the entire list to one server call.
- The Assign node is the only node that changes a variable or Output Parameter value during flow execution; every flow path must terminate at an End node that returns Output Parameters to the caller.
- Switch is cleaner than nested Ifs for multi-value routing on a single expression; use If for boolean conditions or when different branches test different expressions.
Logic Flow Control: If, Switch, For Each, and Assign
Quick Answer: OutSystems action flows are built from four core logic nodes: If (conditional true or false branching), Switch (multi-branch routing based on a single expression's value), For Each (iterate over a record list), and Assign (set a variable or output parameter to a new value). Flow connectors link nodes sequentially, and every flow path ends at an End node. These nodes compose all imperative logic in both Client and Server Actions — mastering when to use each is roughly 10% of the exam (Logic Flows and Exception Handling, 5 questions).
The If Node: Conditional Branching
The If node evaluates a boolean condition and routes execution down one of two paths: True or False. It is the simplest conditional and the workhorse of action flows. Typical uses include checking whether a fetched record exists (If Order.Id <> NullIdentifier() then show it; else show a not-found message), guarding a create versus update decision (If RecordId = NullIdentifier() then Create; else Update), and branching on user role or status.
The condition is an OutSystems expression evaluating to a boolean. If you need more than two outcomes on the same expression, a Switch is cleaner than nested Ifs. The If node on a screen (the If widget) is a separate concept — it conditionally renders UI content, not logic branches; do not confuse the screen If widget with the logic If node even though they share a name.
The Switch Node: Multi-Branch on Value
The Switch node evaluates a single expression and routes to one of several labeled branches based on the expression's value. Each branch has a label matching a specific value; a default path handles unmatched values. Switch is purpose-built for status-code or enum-style routing:
| Scenario | Expression | Branches |
|---|---|---|
| Order status | Order.StatusId | 1=Pending, 2=Approved, 3=Rejected, else=Unknown |
| Day of week | DayNumber | 1=Mon through 5=Fri, else=Weekend |
| Payment method | Payment.MethodId | 1=Card, 2=BankTransfer, 3=Cash, else=Other |
Use Switch when one expression can take a small set of discrete known values. Use If when the condition is a boolean check or when different branches test different expressions. Switch branches are labeled with literal values or Static Entity identifiers; they are not boolean conditions.
The For Each Node: Iterating Lists
The For Each node iterates over a Record List variable, executing the body once per record. Inside the loop, the current record is available through the Current Record element. For Each is the standard way to process a list in a Server Action — for example, validate each line item, accumulate a total, or call a child Server Action per item.
The N+1 Trap
A classic exam scenario: placing a Server Action call inside a For Each loop. Each iteration makes a separate server round-trip, producing the N+1 query problem — one query to fetch the list, then one server call per record. For large lists this causes severe performance degradation. The fix is to pass the entire list to a single Server Action that processes all records in one server-side call, using its own internal For Each to avoid cross-boundary round-trips.
The Assign Node: Setting Variable Values
The Assign node sets a variable to a new value. It can assign to Local Variables within the action and to Output Parameters of the action (to build the return value before the End node). An Assign can set multiple variables in a single node — each assignment is a separate row. The right-hand side is an OutSystems expression evaluated at execution time. Assign is the only node that changes a variable's value during flow execution; everywhere else, variables are read-only.
Screen Input Parameters are read-only within a called action and cannot be assigned; they are inputs, not working storage. To return a computed value, assign it to an Output Parameter and let the End node return it.
Flow Connectors and End Nodes
Nodes are connected by flow connectors — directed arrows showing execution order. A flow starts at the action's entry point (after Input Parameters are bound) and proceeds through connectors. Branching nodes (If, Switch) split the flow; all paths eventually converge or reach an End node that terminates the action flow and returns current Output Parameter values to the caller.
In a Screen Action for Traditional Web, the End node can set a Destination (the screen or URL to navigate to). In Reactive Web Client Actions, navigation is handled by a separate Navigate action node earlier in the flow, not by the End node. A flow with an unconnected path is a TrueChange error — every node must be reachable and every path must terminate at an End node or an Exception Handler exit.
Choosing the Right Node
| Goal | Node |
|---|---|
| Branch on a true or false condition | If |
| Route based on one expression's discrete values | Switch |
| Process every item in a list | For Each |
| Change a variable's value | Assign |
| Return a value from the action | Assign to an Output Parameter, then End |
| Handle an error | Exception Handler (covered in Chapter 6) |
A common mistake is using nested Ifs where a Switch would be clearer — the exam tests whether you recognize that Switch is purpose-built for multi-value routing on a single expression. Another trap: using Assign inside a For Each to accumulate a total works, but for summing or counting, consider an Aggregate with Group By instead — aggregates run in the database and avoid fetching all records to the application server.
An OutSystems Server Action processes invoice records and must route to different branches depending on a PaymentTypeId field (1=CreditCard, 2=WireTransfer, 3=Cheque). Which logic node is the best fit for this routing?
In an OutSystems Reactive Web App, a Client Action iterates over a list of 200 order records using a For Each node and calls a Server Action inside the loop to update each record individually. What is the main problem and the recommended fix?
Which OutSystems logic node is used to set a Local Variable or Output Parameter to a new value during action flow execution?