Breaking Out! Break out of Canvas App code with Error Handling

Breaking Out! Break out of Canvas App code with Error Handling
Play this article

We've all been there, we have a string of functions we need to run in sequence in PowerFx. This is usually doable as we could formulate some logic as we proceed through the code to check the last function worked correctly. However, there's another way to break out of code.

For this to work, we can utilise some error handling and work with the Error() function to make a customised break out whenever we need it. We're going to talk about error handling, and once we have a grasp on how to use it, we'll look at how we can use it to our advantage.

Error handling in PowerFx

Error handling is crucial to ensure your code accounts for the unexpected. No one wants to see generic error messages popup, and incorporating error handling allows us to account for these scenarios, as well as do some more advanced actions like sending to Trace() or giving the user a more meaningful error message.

Before we get into the details, let's look at how we can do a try/catch block in JavaScript. This is a form of error handling where some code is performed, and if it errors, the code in the Catch block is then executed. We also capture the context of the exception.

try{
     //Perform something   
}catch(e){
    //do something when error occurs
}

A try/catch block will run the code in the try clause, and if it errors, the code in the catch clause will be executed. When an error occurs, any code proceeding the error in the try block will not be executed.

But we don't have try/catch blocks in PowerFx, or do we?

Example: No Error Handling

Here's some sample code for an app, it allows a user to enter two numbers and at the click of a button, it performs a division by those two numbers. The button's OnSelect() code is as follows:

Button.OnSelect = txtNumber1 / txtNumber2

This code will work fine, however, we'll run into an issue if we try and divide by 0:

We can use IfError to handle this error better:

IfError()

Here's PowerFx's equivalent Try/Catch block. IfError allows us to run a block of code and then, if an error occurs in that block, perform some other action:

IfError(
    1 / 0,
    Notify(
        "An error occured"))

In the above example, we test the block of code in the first argument (line 2) and if an error occurs, we execute the code in the second argument (Notify).

In the case of IfError, the entire block of code in the first argument is processed and then checked for errors. This is important to remember and works a bit differently from a Try/Catch block in more traditional programming languages.

If we string formula together with semicolons in the first argument, all that code will be evaluated/run before we fall back to the second parameter.

IfError(
    1 / 0; Patch(Table, { Value: 10}),
    Notify("An error occured"))

With this in mind, our example above would execute the Patch statement to the Table data source, even if the first statement errors; because of the way PowerFx works, the entire "block" in the first argument needs to be evaluated to output as a value to the parameter.

We may encounter a scenario where we wish to only perform the patch when the first part of the code doesn't error. This is especially important if that Patch statement were dependent on the outcome of the first part of the code (where we're dividing 1 by 0).

We can overcome this issue by breaking out our code into separate blocks. IfError(), just like If() allows us to continually add conditions and fallbacks inline:

IfError(
    1 / 0,                             //Code block 1
    Notify("An error occured"),        //Fallback for Block 1
    Patch(Table, { Value: 10}),        //Code block 2
    Notify("Another Error Occured"))   //Fallback for Block 2

Our code above is now broken down into separate blocks. This means that if Block 1 fails, we won't execute Block 2.

Getting Error Information

You may have spotted we're responding with error information when we failover during IfError(). We do this with the FirstError App Variable. AllErrors can also be used. However, FirstError is a convenient way to capture the error that's just occurred.

So, what about breaking out? 🦀🧱

We've seen how we can break out of a code cycle with error handling, but we may encounter a scenario where we wouldn't want to continue processing not just because of an error, but because a particular value or condition has/hasn't been met.

Error()

Error() allows us to create custom errors. This allows us to manipulate the IfError function and break out of our code cycle on our terms, rather than errors being produced from our otherwise functioning code.

To use this, we can create our own "errors" using Error() that will break out of IfError when triggered:

With(
    { evaluation: IfError(RandBetween(1,1000) / 5,0)},
    IfError(
        If(evaluation > 100,
            Error( {Kind: ErrorKind.Custom, Message: "Value is over 100"}),
            true),
        Notify(FirstError.Message, NotificationType.Error),
        Notify($"Value is {evaluation}")))

So in our example, we're doing the following:

  • Performing a sum on any random number between 1 and 1000, divided by 5

  • Evaluating if the result is > 100

    • If it is, we generate a custom error, if not we return true.
  • If the error is thrown, our Fallback for Code block 1 will kick in, we won't process the notify code at the bottom of the block

  • If the error didn't occur, we run the code at the end of the block, notifying the user of the resulting number.

This is a basic example, but you may want to employ this in scenarios where you have to patch two different data sources, but the second data source should only be patched following a certain condition following from the first patch, rather than just whether the first patch threw an error or not.

Summary

What did we learn?
We learnt how error handling works and how PowerFx works with blocks of code, which requires a full evaluation before checking for errors. We learnt how we can handle errors with the IfError() function and finally, we looked at how we can both generate errors ourselves and utilise this along with IfError to break out of PowerFx code blocks based on a condition.

That's a wrap!

I hope you found this article helpful not only for breaking out code but understanding error handling in PowerFx in general!

Resources