What is the best way to ensure that a button cannot be clicked more than once?
I have a couple of possible solutions, but wonder if there is a best practice, sure-fire way, of achieving this.
My current approaches:
Approach 1
<Button ux:Name="testbutton" Clicked="{someJsMethod}">
<Clicked>
<Set Target="testbutton.IsEnabled" Value="false"/>
</Clicked>
</Button>
- Pro:
- Declarative
- Uses native UX
- Con:
- Not sure what order things will run in, or if it is deterministic
- Not 100% sure if js won’t be called more than once.
Approach 2
//JS ClickingButton.js
var buttonEnabled = Observable(true);
var buttonClicked=function(){
if(buttonEnabled.value){
buttonEnabled.value = false;
//Do whatever
}
}
module.exports = {
buttonEnabled: buttonEnabled,
buttonClicked: buttonClicked
}
<JavaScript File="ClickingButton.js" />
<Button IsEnabled="{buttonEnabled}" Clicked="{buttonClicked}" />
- Pro:
- Enforces value in JS so I am sure it will not run the JS more than once
- Con:
- More verbose.
- Not declarative
Are any of these the “best practice” or are there other ways of achieving a guaranteed single-fire of a JS method upon a button click?
I would prefer Approach 1. Its simple and the code tells me that the button will be disabled after being clicked once.
Only thing to keep in mind is that this can have an effect on animations. For example:
<Button ux:Name="button">
<Clicked>
<Set button.IsEnabled="false" />
</Clicked>
<WhileEnabled>
<!-- enabled appearance -->
<WhilePressed>
<Scale Factor="2" Duration="2" />
</WhilePressed>
</WhileEnabled>
<WhileDisabled>
<!-- disabled appearance -->
</WhileDisabled>
</Button>
In this case your Set
would immediately stop the animation etc.
But you can fix that by setting a Delay
on Set
https://www.fusetools.com/docs/fuse/triggers/actions/set_1
Would this guarantee that the JS callback <Button Clicked="{someMethod}"
would not be called more than once?
Maybe my problem is that I don’t understand the call-order of things like Set
. What would happen for instance if I clicked with two fingers, or clicked twice really fast? Would the Set
trigger before the second click? Would that still be true if there was a delay?
If there is no delay on Set
, it will happen immediately. It should not prevent any other Clicked
from firing If you need a delay you might want to remove the <Clicked />
after the first firing.
<Button ux:Name="button">
<WhileTrue Value="true" ux:Name="wt">
<Clicked>
<Set wt.Value="false" />
</Clicked>
</WhileTrue>
</Button>
But yeah, if you have a delay on Set
you might end up firing clicked several times