cancel
Showing results for 
Search instead for 
Did you mean: 
LaurensM

Let's tidy up those Power Fx conditional statements

Ah, the good old If & Switch conditional statements! One of the first Power Fx functions you’ll familiarize yourself with when working with Canvas Apps.

 

In this blog post we’ll shortly familiarize ourselves with the Power Fx If and Switch functions. More importantly, we’ll look at some tips & tricks to easily improve code readability and scalability.

 

 

IF FUNCTION

 

The If function allows us to evaluate 1 or more conditions. If a condition returns true, the corresponding value is returned. 

 

Let’s start with a simple example, only containing 1 condition and a true parameter:

 

If(
    <Condition>,
    <TrueParameter>
)
If(
    Slider.Value > 5,
    Notify("The number exceeds 5.")
)

 

An optional Default parameter can be added to return a specific value should none of the defined conditions return true. If none of the conditions return true and no default value is defined, the function returns blank.

 

If(
    <Condition>,
    <TrueParameter>,
    <DefaultParameter>
)
If(
    Slider.Value > 5,
    Notify("The number exceeds 5."),
    Notify("The number does not exceed 5.")
)

 

You are able to define multiple conditions by adding them as additional parameters after the previous ‘True Parameter’:

 

If(
    <Condition1>,
    <TrueParameter1>,
    <Condition2>,
    <TrueParameter2>,
    <DefaultParameter>
)
If(
    Slider.Value > 10,
    Notify("The number exceeds 10."),
    Slider.Value > 5,
    Notify("The number is between 6 and 10"),
    Notify("The number does not exceed 5.")
)

 

 

SWITCH FUNCTION

 

The Switch function is used to evaluate a single condition against multiple, possible matches. The function goes through the possible matches and returns the corresponding value once it finds a match.

 

If no match is found it will default to the optional default value – or blank should no default value be defined.

 

Switch(
    <Condition>,
    <Case1>,
    <Result1>,
    <Case2>,
    <Result2>,
    <DefaultResult>
)
Switch(
    gblRole,
    "Admin",
    Navigate('Admin Screen'),
    "Manager",
    Navigate('Manager Screen'),
    "User",
    Navigate('User Screen'),
    Navigate('No Role Error Screen')
)

 

 

TIPS & TRICKS

 

Within this section we’ll explore some tips that will improve your code readability and reduce the code within your conditional statements.

 

Avoid unnecessary if statement nesting

 

Within more complex scenarios it is certainly possible that you may need multiple conditional statements. A case that I often observe is if statement nesting when condition chaining would suffice:

 

//Avoid the following scenario:
If(
    Slider.Value > 10,
    Notify("The number exceeds 10."),
    //Redundant If() nesting
    If(
        Slider.Value > 5,
        Notify("The number is between 6 and 10"),
        Notify("The number does not exceed 5.")
    )
)

 

As we’ve learned in the if statement section, we can supply the function with multiple conditions. Using this approach we can refactor the previous code as follows:

 

If(
    Slider.Value > 10,
    Notify("The number exceeds 10."),
    Slider.Value > 5,
    Notify("The number is between 6 and 10"),
    Notify("The number does not exceed 5.")
)

 

 

Don’t forget about the Switch function

 

Now that we’ve seen the syntax for evaluating multiple conditions via the If statement, it may be tempting to forget about the Switch function altogether. When evaluating the same condition against a number of different values, however, stick to the Switch function.

 

//If() used to evaluate a single condition
If(
    gblRole = "Admin",
    Navigate('Admin Screen'),
    gblRole = "Manager",
    Navigate('Manager Screen'),
    gblRole = "User",
    Navigate('User Screen'),
    Navigate('No Role Error Screen')
)

 

Although an if could be used by repeating the condition, a switch statement:

 

  • Reduces the amount of code written
  • Improves code readability
  • Creates a clear distinction between single condition evaluations and more complex conditions

 

Switch(
    gblRole,
    "Admin",
    Navigate('Admin Screen'),
    "Manager",
    Navigate('Manager Screen'),
    "User",
    Navigate('User Screen'),
    Navigate('No Role Error Screen')
)

 

 

Don't return booleans

 

If and Switch functions should not be used to return a boolean value as the condition itself returns one already. Below we can see an if statement that checks whether colEmails contains the current user’s email.

 

//Example of returning booleans
If(
    User().Email in colEmails,
    true,
    false
)

 

This code can easily be shortened by removing the If function and output parameters altogether:

 

//Returns a boolean
User().Email in colEmails

 

I most often see If conditions being used in this context when you would like to invert the boolean output. This can be avoided by prefixing your condition with the not operator:

 

//Don’t do this:
If(
    User().Email in colEmails,
    false,
    true
)

//Do this instead:
!(User().Email in colEmails)

 

 

Avoid redundant default parameters

 

When building Switch and If statements remember that the default parameter is optional. When no default parameter is given and no match is found, blank is returned.

 

Although the first code example below will work, it is best to remove the third parameter.

 

//Don’t do this:
If(
    Slider.Value > 20,
    Notify("The number exceeds 20."),
    ""
)

//Do this instead:
If(
    Slider.Value > 20,
    Notify("The number exceeds 20.")
)

 

 

Coalesce a day keeps the if statement away

 

In certain cases, another function may provide the same functionality whilst avoiding a conditional statement. 

 

One function that instantly comes to mind is the Coalesce function. This function returns the first value that is not blank or an empty string. This avoids the longer if statement alternative in which each value evaluation has to be written manually in the condition parameters.

 

//Don't do this:
If(
    !IsBlank(txtAddress.Text),
    txtAddress.Text,
    !IsBlank(txtSecondAddress.Text),
    txtSecondAddress.Text
)

//Do this instead:
Coalesce(
    txtAddress.Text,
    txtSecondAddress.Text
)

 

 

[Optional] Split the conditional logic across properties

 

What I commonly observe is that all of the conditional logic is crammed into a single behavior property. (e.g. the OnSelect of a button)

 

In the high-level example below, we have an app with separate text input controls for data entry. In the OnSelect of our save button we first check whether all required fields are not empty after which we save the entry into a different datasource depending on the second condition.

 

If(
    //Check whether all required fields are not empty
    !IsBlank(...) && !IsBlank(...) && !IsBlank(...),
    If(
        //Check our fictive condition
        <Condition>,
        Patch(
            Datasource1,
            Defaults(Datasource1),
            {
                //Our columns & values
            }
        ),
        Patch(
            Datasource2,
            Defaults(Datasource2),
            {
                //Our columns & values
            }
        )
    ),
    Notify("Please fill in all required fields.", NotificationType.Error, 5000)
)

 

This part is completely optional but is a strategy you could implement to avoid hoarding all conditional logic into a single property.

 

Instead of responding via a notification, you could proactively inform the user by displaying an error label and disabling the button. This way (1) the user has instant visual feedback, (2) we can move some of the conditional logic to other properties.

 

The button’s OnSelect would retain only the core patch logic:

 

//Run code when all required fields are filled in (cfr. DisplayMode)
If(
    <Condition>,
    Patch(
        Datasource1,
        Defaults(Datasource1),
        {
            //Our columns & values
        }
    ),
    Patch(
        Datasource2,
        Defaults(Datasource2),
        {
            //Our columns & values
        }
    )
)

 

The button’s DisplayMode in combination with a visual label will be used to indicate when certain required fields are left empty.

 

The button’s DisplayMode will contain the required field logic:

 

If(
    //Check whether all required fields are filled in
    !IsBlank(...) && !IsBlank(...) && !IsBlank(...),
    DisplayMode.Edit,
    //Disable button - displaying error label
    DisplayMode.Disabled
)

 

We don’t have to rewrite all of the conditional logic used in the code above. The label’s visible property will depend on the button’s DisplayMode.

 

//Display error when button is disabled
ButtonName.DisplayMode = DisplayMode.Disabled

 

The example above is just one of many cases in which you can split some of the logic across properties or even controls to avoid a bloated behavior property. Although reducing the amount of code in a behavior property makes the core behavior code more readable (Patch in our case), splitting our logic into separate properties may make it more difficult to understand the code later on

 

When following this approach, make sure it is well documented – especially in more complex scenarios. One way of doing this is by providing a link between the properties through comments, as was done in the code above.

 

If you liked this blog post, feel free to give it a like👍 | For more tips and tricks check out my blog (LaurensM)📘