DEV Community

Cover image for Power Apps, How many ways to make a Calculator
david wyatt
david wyatt Subscriber

Posted on • Edited on

Power Apps, How many ways to make a Calculator

LowCode is sometimes thought of as simple and repeatable. There are fewer building blocks so there is only one way to solve a problem. And although this is kind of true, it's not quite. 9 times out of 10 there will be an out of the box solution, that is quick and easy to implement, but there are times and ways to be more creative. And that is where most of the fun comes from 😎

One of the few missing out of the box solutions in Power Apps is calculators, so I thought I would look at all the different ways we could create a calculator, and what I can learn.

So how many ways can you create a calculator, well I found at least 5:

  1. Standard Buttons
  2. Gallery
  3. Code
  4. Timer
  5. Abacus 🧮

1. Standard

Animated gif of Power App calculator

The idea is pretty simple, each number and operator is its own button component. We have 5 variables:#

  • vsOne = First number
  • vsTwo = Second number (set to 99999999999999999999 so we know it's not used)
  • vsCalc = Operator
  • vsEquals = Show result
  • viValue = result

In a nut shell we hold first value in vsOne and on operator we store operator and set vsTwo to "" and store next numbers in there. Then on equals we use switch based on operator to complete the action.

Reset Button



Set(vsOne,"0");
Set(vsTwo,"99999999999999999999");
Set(vsCalc,"");
Set(vbEquals,false);
Set(viValue,0);


Enter fullscreen mode Exit fullscreen mode

Number Button



If(vsTwo="99999999999999999999",
    Set(vsOne,Value(vsOne& Self.Text)&"")
,
    Set(vsTwo,Value(vsTwo& Self.Text)&"")
)


Enter fullscreen mode Exit fullscreen mode

Operator Button (+)



Set(vsCalc,Self.Text);   
If(vsTwo="99999999999999999999",       
    Set(vsTwo,"0");
,
    Set(viValue,Value(vsOne) + Value(vsTwo));
    Set(vsOne,viValue&"");
    Set(vsTwo,"0");
)


Enter fullscreen mode Exit fullscreen mode

Equals Button



Switch(vsCalc,
    "+",Set(viValue,Value(vsOne) + Value(vsTwo)),
    "-",Set(viValue,Value(vsOne) - Value(vsTwo)),
    "*",Set(viValue,Value(vsOne) * Value(vsTwo)),
    "/",Set(viValue,Value(vsOne) / Value(vsTwo))
);
Set(vsOne,viValue&"");
Set(vsTwo,"99999999999999999999");


Enter fullscreen mode Exit fullscreen mode

2. Gallery

Gallery based caculator

The Gallery approach is similar to the buttons, but has the advantage of automatically positioning all the buttons.

The gallery requires the following array of items:
["1","2","3","4","5","6","7","8","9","0","+","-","/","*","=","C"]

We then roll all the OnSelect code as they all the buttons use the same code.

All Buttons



If(IsNumeric(Self.Text),
    If(vsTwo="99999999999999999999",
        Set(vsOne,Value(vsOne& Self.Text)&"")
    ,
        Set(vsTwo,Value(vsTwo& Self.Text)&"")
    )
,
    If(Self.Text="=",
        Switch(vsCalc,
            "+",Set(viValue,Value(vsOne) + Value(vsTwo)),
            "-",Set(viValue,Value(vsOne) - Value(vsTwo)),
            "*",Set(viValue,Value(vsOne) * Value(vsTwo)),
            "/",Set(viValue,Value(vsOne) / Value(vsTwo))
        );
        Set(vsOne,viValue&"");
        Set(vsTwo,"99999999999999999999");
    ,
        If(Self.Text="C",
            Set(vsOne,"0");
            Set(vsTwo,"99999999999999999999");
            Set(vsCalc,"");
            Set(vbEquals,false);
            Set(viValue,0);
            Set(sPrint,"");
        ,
            Set(vsCalc,Self.Text);   
            If(vsTwo="99999999999999999999",       
                Set(vsTwo,"0");
            ,
                Switch(Self.Text,
                    "+",Set(viValue,Value(vsOne) + Value(vsTwo)),
                    "-",Set(viValue,Value(vsOne) - Value(vsTwo)),
                    "*",Set(viValue,Value(vsOne) * Value(vsTwo)),
                    "/",Set(viValue,Value(vsOne) / Value(vsTwo))
                );
                Set(vsOne,viValue&"");
                Set(vsTwo,"0");
            )
        )           
    )
)


Enter fullscreen mode Exit fullscreen mode

3. Code

Animited gif of keyboard based calculator

This one I personally think is pretty cool, instead of using buttons why not user the keyboard.

We have a similar approach but this time we don't save to variables but a single row in a collection

Unfortunately there was no easy way to use a Regex (well one I could find) so my approach was to split the input into an array and then loop over each character, saving/appending to the single row array (which we use as an object to store variables as you can't set in a ForAll loop). The logic is

  • If is number and no operator saved append to key one (as this is the first number in the formula)
  • If is number but operator saved append to key two (as this is the second number in the formula)
  • Else set to operator (as we know its not a number)
  • After ForAll finished use operator to select formula and display results

Loop logic diagram

Equals Button



ClearCollect(colInput,Split(inCalcCode.Text,""));
Set(viValue,0);
ClearCollect(colResult,{one:"",operator:"",two:"",value:0,id:1});
ForAll(colInput,
    If(IsNumeric(ThisRecord.Value)&&Index(colResult,1).operator="",
        Patch(colResult,{id:1},{
            one:Index(colResult,1).one&ThisRecord.Value}
        )
    ,
        If(IsNumeric(ThisRecord.Value),
            Patch(colResult,{id:1},{
                two:Index(colResult,1).two&ThisRecord.Value}
            )
        ,
            Patch(colResult,{id:1},{
                operator:ThisRecord.Value}
            )
        )
    )
);
Switch(Index(colResult,1).operator,
    "+",Set(viValue,Value(Index(colResult,1).one) + Value(Index(colResult,1).two)),
    "-",Set(viValue,Value(Index(colResult,1).one) - Value(Index(colResult,1).two)),
    "*",Set(viValue,Value(Index(colResult,1).one) * Value(Index(colResult,1).two)),
    "/",Set(viValue,Value(Index(colResult,1).one) / Value(Index(colResult,1).two))
);
Set(vbResult,true);



Enter fullscreen mode Exit fullscreen mode

4.Timer

Timer based power app calculator

As I have mentioned before, Timers are another more flexible way to do loops in Power Apps.
The approach is similar to the Code (ForAll loop) approach with a few small differences.

As this is more a For loop we don't increment over each item but count and do an index comparison. And as we can now Set variables we don't need our single row collection.

Equals Button



ClearCollect(colInput,Split(inCalcTimer.Text,""));
Set(vsOne,"");
Set(vsNumber,"");
Set(viValue,0);
Set(i,1);
Set(vbResult,false);
Set(vsCalc,"");
Set(vbCalc,true);


Enter fullscreen mode Exit fullscreen mode

This time we are going to:

  • Incement over every item from the split string. When we hit the length we stop the loop, select the formula and show the result.
  • If less then length we check if is number and vsCalc is blank (as then we know if first or second part of formula).
  • If it is both we append to vsNumber
  • If it is number but vsCalc is not blank then we check to see if vsOne is blank, if it is we copy vsNumber over and clear vsNumbner (ready for second number in formula). Then we append again to vsNumber.
  • Finally if it is not numeric then we save is as vsCal as we know it is the operator.

Timer Loop process
Start



vbCalc


Enter fullscreen mode Exit fullscreen mode

Repeat



vbCalc


Enter fullscreen mode Exit fullscreen mode

OnTimerEnd



If(i>CountRows(colInput),
    Set(vbCalc,false);
    Set(vbResult,true);
    Switch(vsCalc,
        "+",Set(viValue,Value(vsOne) + Value(vsNumber)),
        "-",Set(viValue,Value(vsOne) - Value(vsNumber)),
        "*",Set(viValue,Value(vsOne) * Value(vsNumber)),
        "/",Set(viValue,Value(vsOne) / Value(vsNumber))
    );
    Reset(inCalcTimer);
,
    If(IsNumeric(Index(colInput,i).Value),
        If(vsCalc="",
            Set(vsNumber,vsNumber&Index(colInput,i).Value);
        ,
            If(vsOne="",Set(vsOne,vsNumber);Set(vsNumber,""));
            Set(vsNumber,vsNumber&Index(colInput,i).Value);          
        )
    ,
          Set(vsCalc,Index(colInput,i).Value)  
    )
);
Set(i,i+1);


Enter fullscreen mode Exit fullscreen mode

5.Abacus

Want to go truly innovative, then lowCode and Power Apps has got your back. Why use a calculator when you can use an abacus.

Animated gif of abacus app

The abacus is built by aligning 2 gallery's, with the right the unused beads and the left used.
The gallery is populated by 2 matching collections

Screen OnVisible / Clear Button OnSelect



ClearCollect(colSelected,
    {type:"ones",show:"|",val:""},
    {type:"tens",show:"X",val:""},
    {type:"hundreds",show:"C",val:""},
    {type:"thousands",show:"M",val:""},
    {type:"tenthousnads",show:"̅X̅",val:""}
);
ClearCollect(colUnSelected,
    {type:"ones",show:"|",val:"||||||||||"},
    {type:"tens",show:"X",val:"XXXXXXXXXXX"},
    {type:"hundreds",show:"C",val:"CCCCCCCCCC"},
    {type:"thousands",show:"M",val:"MMMMMMMMMM"},
    {type:"tenthousnads",show:"̅X̅",val:"X̅X̅X̅X̅X̅X̅X̅X̅X̅X̅"}
)


Enter fullscreen mode Exit fullscreen mode

The gallery has a lable showing the collection val, on Select of the label with patch the value with length -1 and patch the other collection with its val and the show.

Gallery label OnSelect



If(ThisItem.val<>"",
    Patch(colUnSelected,{type:ThisItem.type},
        {val:Left(ThisItem.val,Len(ThisItem.val)-1)}
    );
    Patch(colSelected,{type:ThisItem.type},
        {val:LookUp(colSelected,type=ThisItem.type).val&ThisItem.show}
    );
)


Enter fullscreen mode Exit fullscreen mode

The last step is converting the colSelected item val's to a number.

Text of Result label



(Len(Index(colSelected,1).val)*1)+
(Len(Index(colSelected,2).val)*10)+
(Len(Index(colSelected,3).val)*100)+
(Len(Index(colSelected,4).val)*1000)+
(Len(Index(colSelected,5).val)*10000/2)


Enter fullscreen mode Exit fullscreen mode

As you can see there are loads of different ways to solve any App solution, it shows how important a good design review is to help plan before development.

A copy of the app can be found here

Top comments (4)

Collapse
 
jaloplo profile image
Jaime López

Love so much your post.

I will challenge you to add the following way if you can: Cistercian Numerals. Take a look on it and share with us the solution, if it has any ;)

Collapse
 
wyattdave profile image
david wyatt

Now that looks like a fun challenge 😀

Collapse
 
balagmadhu profile image
Bala Madhusoodhanan

Love the Abacus version :-)

Collapse
 
bilalq profile image
Bilal Qureshi

it has rather interesting results if we try to add more than 2 variables like 1+2+2+3 or use brackets (). Still a very interesting and good approach