はじめに
Visualforceで画面を作成していて、実行ボタンが2度押しされたことはないでしょうか?
ブラウザのタブで実行中のクルクルが回ってますが、あれ押したかな?動いているのかな?とユーザはお構いなしにボタンを何度も押すことが多いようです。
その対策として、ユーザにも分かりやすいように、処理中だと画面で分かるようにし
かつ、2重実行が出来ないようにしたいと思います。
※Lightning Web Conponent等を利用すれば簡単にできそうですが
すでにVisualforceで作成してしまっているので、そちらで実現をしたいと思います。
いろんなやり方はあると思いますが、今回は動画ファイル不要のCSSだけのもので実現をしています。
実装概要
実行ボタンを押した時に、実行中を示す(スピナー)を表示させ、ユーザの2度押しを防止する。
実装イメージ
サンプルコード
<apex:page lightningStylesheets="true" docType="html-5.0" recordSetVar="tests" standardController="test__c" extensions="TestDataCreate">
<!-- jQuery -->
<apex:includeScript value="{!$Resource.jquery}"/>
<apex:form >
<apex:pageMessages />
<apex:pageBlock >
<apex:pageBlockSection >
<apex:selectList value="{!year}" size="1" label="年度">
<apex:selectOptions value="{!yearList}" />
</apex:selectList>
</apex:pageBlockSection>
<apex:pageBlockButtons location="bottom">
<apex:commandButton value="作成" onclick="return confirmExecAction();" action="{!create}"/>
</apex:pageBlockButtons>
</apex:pageBlock>
</apex:form>
<div id="overlay">
<div class="cv-spinner">
<span class="spinner"></span>
</div>
</div>
<script type="text/javascript">
// action実行確認
function confirmExecAction() {
if (window.confirm("実行します。よろしいですか?")) {
$("#overlay").fadeIn(500); //二度押しを防ぐloading表示
setTimeout(function() {
$("#overlay").fadeOut(20000);
}, 20000);
return true;
}
return false;
}
</script>
<style>
#overlay{
position: fixed;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height:100%;
display: none;
background: rgba(0,0,0,0.6);
}
.cv-spinner {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.spinner {
width: 80px;
height: 80px;
border: 4px #ddd solid;
border-top: 4px #999 solid;
border-radius: 50%;
animation: sp-anime 0.8s infinite linear;
}
@keyframes sp-anime {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
.is-hide{
display:none;
}
</style>
</apex:page>
説明
<apex:pageBlockButtons location="bottom">
<apex:commandButton value="作成" onclick="return confirmExecAction();" action="{!create}"/>
</apex:pageBlockButtons>
onclickで実行確認のダイアログ、スピナー実行のjavascriptを呼び出しています。
<!-- jQuery -->
<apex:includeScript value="{!$Resource.jquery}"/>
jQueryを使用している為、登録済み静的リソースを呼び出し
<style>
#overlay{
position: fixed;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height:100%;
display: none;
background: rgba(0,0,0,0.6);
}
.cv-spinner {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.spinner {
width: 80px;
height: 80px;
border: 4px #ddd solid;
border-top: 4px #999 solid;
border-radius: 50%;
animation: sp-anime 0.8s infinite linear;
}
@keyframes sp-anime {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
.is-hide{
display:none;
}
</style>
spinner用cssです。
<script type="text/javascript">
// action実行確認
function confirmExecAction() {
if (window.confirm("実行します。よろしいですか?")) {
$("#overlay").fadeIn(500); //二度押しを防ぐloading表示
setTimeout(function() {
$("#overlay").fadeOut(20000);
}, 20000);
return true;
}
return false;
}
</script>
確認ダイアログを表示
・OK ・・・ spinnerを表示させ、actionを実行
・キャンセル ・・・ actionを中止
今回処理時間が長めなのでtimeout値を多めにとっています。
CSSは直接書いていますが、複数の機能で使用する場合は、共通のCSSとして静的リソースに登録をしてしまったほうがよいかと思います。
その他
今回は使用していないので未検証ですが、ajaxを利用する場合は以下のようなコードになります。
<script>
$(".sbmitbtn").on("click", function(){
$(document).ajaxSend(function() {
$("#overlay").fadeIn(500);
});
$.ajax({
type: 'GET',
success: function(data){
console.log(data);
}
}).done(function() {
setTimeout(function(){
$("#overlay").fadeOut(500);
},3000);
});
return false;
});
</script>