Blog

Functions - How to create and use 'user defined functions'

We can define ‘user-defined functions’ that encapsulate logic and formula in a single place. We can then call the function from multiple places throughout an app, which improves the quality of our apps by reducing code duplication. In this post, we'll walk through an example of how to create a user defined function, and we'll also examine some of the limitations.

A long-awaited feature is the ability to create user defined functions. At present, the only practical way to reuse complex formulas is to copy and paste the formula throughout all the places where we want to use it.

If we want to apply a fix that affects all instances of a formula, it can be very difficult, especially given that there isn't a a find and replace feature in Power Apps Studio.

The great news is the 'user defined functions' feature is now in preview. In this post, we’ll walk through an example of how to define a user defined function, and we'll examine some of the current limitations.

Enabling user defined functions.

The first step is to enable the user defined function setting in the advanced settings of the app designer. Once we do this, we can start to build user defined functions through the components section of the app designer.

Creating a user defined function

To demonstrate, we’ll build a function that converts miles to kilometres. Here’s the target signature of the function that we'll create:
MilesToKMs(inputMiles)
----------------------------
Argument name: inputMiles (required) - the value in miles to convert to kilometres

From within our app, we add a component to host our 'user defined function'. In this example, we'll call the component 'utils'.

We want to create function that returns a number. Therefore, we must define an output property with a name that matches the target name of the function (MilesToKMs).


The definition of our function includes an input parameter called inputMiles. To define this, we click the 'new parameter' option from within the MilesToKMs output.

To define the logic that carries out the calculation, we add the formula to the MilesToKMs property.

Calling the user-defined function

To call a user defined function, we add the component to a screen through the insert > custom menu item in the left-hand panel. We can then reference the user defined function through the instance of the component. The example beneath shows how to call the user defined function on a label, in order to convert the value of a text input control into kilometres.


A great thing is that it’s possible to refer to the component from items within a gallery, and from within function calls. As this screenshot shows, it’s possible to refer to the user defined function from inside a call to the AddColumns function, and to display the output in a data table.

Are there any limitations?

An inherent limitation of components is that from within a component, we cannot access data sources or objects from the host screen or app. Whilst experimenting with this feature, some areas that I found challenging include the following.

Building logic with many steps that includes behaviour functions can be hard to implement. For example, let’s suppose we want to build a function that converts an image to a base64 string, with a signature that looks like this.
ConvertToBase64String (inputImage)

With this type of use case scenario, we would need to develop a workaround to call the JSON logic from elsewhere.


The second challenge is that it isn’t possible to define generic input parameters of type table. As an example, it would be great if we could define a function that returns the specified row from an input table by ordinal number like so:
GetOrdinal(inputDataTable, rowNumber)
This would encapsulate the Last/FirstX pattern that we use commonly use.The issue here is that we must define a hard-coded schema for the input table parameter, and therefore, we cannot define functions that accept generic tables.

Conclusion

Despite the minor bugs and limitations, the ‘user-defined function’ feature provides an enormous improvement over what we currently have. I'm delighted by this feature, and it is definitely a very welcome addition to the product. Well done to the Power Apps team for building this feature!