How to avoid code duplication in PowerApps

If you’re developing PowerApps you must at least once find yourself in a situation of having multiple different controls executing same or similar code. In this post I want to answer to following questions:

  • Is code duplication that bad?
  • When PowerApps Components are not enough to avoid code duplication?
  • What is another way to centrally manage code in PowerApps

Is code duplication that bad ?

I’ll answer this question using my case when I’ve made a PowerApp app that calls SharePoint Search REST API (via Microsoft Flow) and display results. App looks like this:

As you can see you can search for specific phrase, limit items per page and navigate between result pages. Let’s stop for a second on pagination feature. How do you think – how it was built? Probably most of you will quickly figure out that pagination is nothing else than searching with a “number of items to skip” parameter. Knowing that, you can think of the “Search” button as searching with a 0 (zero) items to skip. In other words – we need 3 buttons with very similar code. Below I present such code – please notice comments I’ve provided:

//clear search results collection
Clear(colSPSearchResultItems);
//read row limit number from input text box and save as variable
Set(gblRowLimitNumber,numRowLimitNumber.Text);
//make call to SharePoint Search and save results in variable. 
//Flow has following parameters: Search_Query, Row_Limit, Row_To_Skip)
Set(gblSearchResults,Searchforitemsintenant.Run(txtSearchPhrase.Text,gblRowLimitNumber,Text(gblItemsToSkip)));
//Now we need to extract values from results string and save as separate //column in table
ClearCollect(
    colSPSearchResultItems,
    AddColumns(
        Split(
            gblSearchResults.results,
            "/n"
        ),
        "UniqueId",
        First(Split(Last(Split(Result,Char(34)&"UniqueId"&Char(34)&","&Char(34)&"Value"&Char(34)&Char(58)&Char(34))).Result,Char(34)&","&Char(34)&"ValueType")).Result,
        "Title",
        First(Split(Last(Split(Result,Char(34)&"Title"&Char(34)&","&Char(34)&"Value"&Char(34)&Char(58)&Char(34))).Result,Char(34)&","&Char(34)&"ValueType")).Result,
        "OriginalPath",
        First(Split(Last(Split(Result,Char(34)&"OriginalPath"&Char(34)&","&Char(34)&"Value"&Char(34)&Char(58)&Char(34))).Result,Char(34)&","&Char(34)&"ValueType")).Result,
        "Rank",
        First(Split(Last(Split(Result,Char(34)&"Rank"&Char(34)&","&Char(34)&"Value"&Char(34)&Char(58)&Char(34))).Result,Char(34)&","&Char(34)&"ValueType")).Result
    )
);

This code realize everything I needed. Although implementing it was not a big deal (I’ve done it once and copied 2 more times), debugging and further maintenance was a nightmare. Every time a change done in one of those buttons had to be copied to the others. When at some point something broke up (ie. some results were wrongly parsed) I was reviewing all 3 copies of the same code just to make sure it is the same (sic!).

Mastering PowerApps Components you must

Yoda has spoken. And at some point he is right – PowerApps Components are very good way to avoid code duplication. Especially if you know PAC development patterns I described in my previous post.

Yep, this is how it was, I didn’t make it up…

BUT! What if you have totally different controls ie. a shape, a button and a gallery and all of them should use the same code. PAC are good until you want to have different properties per control (i.e customize button text in one control and image in another) so this won’t work for such control set.

In such situation I have a recommendation for you.

Centrally managed code in PowerApps

To build centrally managed code in PowerApps follow below steps:

  • Add a new button and make it invisible
  • Put your redundant formula in OnSelect event of the button
  • Use Select(YourInvisibleButton) function to execute formula inside OnSelect event of your invisible button
  • For any dependencies (you can think of them as the functions arguments) use variables (global or local). Ie.
UpdateContext({locSumArg1:4,locSumArg2:6});
Select(btnSumArg1Arg2)

Using presented approach, my “next page” icon code from example search app, looks like this:

//Set items to skip in variable
Set(gblItemsToSkip,gblItemsToSkip+numRowLimitNumber.Text); 
//Call button that contains parameterized arguments
Select(btnCallFlow)

Code of my “previous page” icon is almost the same (the only difference is the minus sign instead of a plus)

Set(gblItemsToSkip,gblItemsToSkip-numRowLimitNumber.Text); Select(btnCallFlow)

4 lines of centrally managed code instead of ~50 lines.
Simple. Clean. Beautiful.

Nothing is perfect

Described method won’t work if you would use variables to pass some “arguments” followed by Select function inside Concurrent function in the same time. It’s obvious but worth to mention just in case.

As Dwight from The Office would say 🙂

And that’s it! I hope you enjoy this post.

Let me know in the comments if you like this approach or not.