Clean GatePass Entry Time Validation with With()

A practical Power Fx pattern for turning GatePass date, gate, section, and request status rules into readable validation logic.

Form validation often starts out simple, then becomes harder to maintain as more business exceptions are added.

I had this situation with a GatePass form. The validation depended on the entry date, the selected access gate, the selected section, and the current request status.

The first version worked, but it used manual If / Else style logic. As the rules grew, the formula became harder to scan. I wanted the validation to read more like the actual business requirement.

The Requirement

The form should be valid only when the entry date is today or in the future.

After that, one of these conditions must also be true:

  • the entry date is 48 hours or more ahead
  • the AAIA gate is Not Required and the entry date is at least 24 hours ahead
  • the section is VIP, the request status is Returned, and the entry date is at least 24 hours ahead

In plain language:

Entry date must not be in the past.

Then allow the request if:
- it is at least 48 hours ahead, or
- AAIA is not required and it is at least 24 hours ahead, or
- it is a returned VIP request and it is at least 24 hours ahead.

Why the Original Logic Became Hard to Read

When this kind of rule is written directly inside nested If statements, the business meaning gets buried.

The formula has to keep checking the same things:

  • how many days ahead the entry date is
  • whether the selected section is a VIP section
  • whether the request was returned
  • whether AAIA access is not required

None of those checks are complicated on their own. The problem is repetition. Once the same conditions appear in several branches, it becomes easier to make a mistake when the rule changes later.

Refactoring with With()

Power Fx With() is useful when a formula needs temporary names for important intermediate values.

Instead of repeating the checks throughout the formula, I can define them once:

Set(
    varIsValidEntryTime,
    With(
        {
            daysAhead: DateDiff(Today(), dtEntryDate.SelectedDate, TimeUnit.Days),
            isVIPSection: !IsBlank(
                LookUp(
                    tblVIP,
                    Upper(Value) = Upper(ddSection.Selected.Value)
                )
            ),
            isReturned: recCurrentRequest.Status.Value = "Returned",
            isAAIANotRequired: ddEntryGateAAIA.Selected.Value = "Not Required"
        },
        daysAhead >= 0 &&
        (
            daysAhead >= 2 ||
            (daysAhead >= 1 && isAAIANotRequired) ||
            (daysAhead >= 1 && isVIPSection && isReturned)
        )
    )
);

This version has two clear parts:

  1. Define the values needed for the validation.
  2. Apply the validation rule using those names.

That makes the formula much easier to read. The second half now looks very close to the requirement itself.

Reading the Final Rule

The first check blocks past dates:

daysAhead >= 0

After that, the form is valid when any of the allowed timing rules passes:

daysAhead >= 2 ||
(daysAhead >= 1 && isAAIANotRequired) ||
(daysAhead >= 1 && isVIPSection && isReturned)

That translates to:

  • allow normal requests when they are at least 48 hours ahead
  • allow requests at least 24 hours ahead when AAIA access is not required
  • allow returned VIP requests at least 24 hours ahead

The temporary names make the intent obvious. isVIPSection, isReturned, and isAAIANotRequired are much easier to understand than repeating each full lookup or dropdown expression inside the validation rule.

A Note on DateDiff

This formula uses:

DateDiff(Today(), dtEntryDate.SelectedDate, TimeUnit.Days)

That gives the number of calendar days between today and the selected entry date.

For this GatePass rule, that works because the requirement is based on selected dates:

  • today gives 0
  • tomorrow gives 1
  • the day after tomorrow gives 2

So daysAhead >= 2 represents 48 hours or more ahead at the date level, and daysAhead >= 1 represents at least 24 hours ahead.

If the form later starts validating exact entry times as well as dates, this logic should be reviewed. At that point, the formula may need Now() and date-time values instead of Today() and selected dates only.

Result

The validation is now easier to maintain because each business concept has a name.

Instead of reading a long nested formula and mentally translating each condition, I can read the final rule directly:

daysAhead >= 0 &&
(
    daysAhead >= 2 ||
    (daysAhead >= 1 && isAAIANotRequired) ||
    (daysAhead >= 1 && isVIPSection && isReturned)
)

That is the part I want future me to find quickly.

Takeaway

With() is a good refactoring tool when a Power Fx formula has several business rules competing for space.

It helps when:

  • the same calculation is needed more than once
  • a lookup or dropdown check makes the formula noisy
  • validation logic has multiple exceptions
  • the final expression should read like the business requirement

The app behavior did not need to change. The main improvement was clarity. By naming the pieces of the rule first, the final validation became clean, readable, and much easier to revisit later.