LoginSignup
2
2

OutSystemsでカウントダウンタイマーを作成する

Last updated at Posted at 2023-06-23

やりたいこと

OutSystemsでスクリーン上にカウントダウンタイマーを表示します。
こんなの
image.png
image.png
image.png

概要

JavaScriptのSetIntervalを利用して、1秒おきにスクリーンのexpressionに設定してあるLocal Variableを更新します。
仕組みはこれだけ。単純です。

プログラムの構成

Screen

image.png
image.png

Local Variable

  • InputSec
    • Integer
    • ユーザが入力するカウントダウン秒数。
    • InputウィジェットのVariableに指定。
  • CountdownSec
    • Integer
    • 実際のカウントダウンで更新される秒数。InputSecがコピーされて1秒おきに1ずつ減らされる。
    • Expressionに指定。
    • Default Value: -1

Expression

  • カウントダウン数値表示
    • Substr("0" + Max(CountdownSec, 0), Length("0" + Max(CountdownSec, 0)) - 2, 2)
    • CountdownSecは初期表示時-1なので、マイナス値を0に変換してから利用。
    • 何となく"00"表示にしたかったので、左に0パディングしています。
  • "Finished!"表示
    • If(CountdownSec = 0, "Finished!", "")
    • 実行中は表示したくないため、CountdownSec0の場合のみ表示。この条件だけだと初回表示時も「Finished!」などとアホくさい表示がドヤ顔でされてしまうため、CountdownSecを初期値-1にし、0になるのは実行完了した時だけになるようにしました。

その他

  • 細かいことですが、[Start]ボタンのEnabledにCountdownSec <= 0を指定することでカウントダウン実行中はボタンが使用不可となり、多重起動を防止することができます。

Client Action

StartOnClick

image.png

  1. InputSecのバリデーション(1以上であること)
  2. CountdownSecInputSecをAssign
  3. JavaScript呼び出し

JavaScript

Countdown.js
console.log("[START]");
console.log($parameters.CountdownSec);

const timerId = setInterval(() => {
    if ($parameters.CountdownSec > 0) {
        $parameters.CountdownSec--;
        $actions.CountdownExec();
        console.log($parameters.CountdownSec);
    } else {
        clearInterval(timerId);
        console.log("[END]");
    }
}, 1000);
JavaScrip Input Parameter
  • CountdownSec
    • Integer
    • Local Variable InputSecまたはCountdownSecを指定。どちらも直前のAssignで同値になっているのでどっちでもいいです。

SetIntervalを引数1000msで呼び出すことで1秒おきに処理を発生させ、その中で受け取ったパラメータ値をデクリメントしつつClient Actionを呼び出します。実際の表示用Local Variable CountdownSecは呼び出したClient Action CountdownExecの中で更新します。
パラメータ値が0になったら処理は終了。この時、SetInterval呼び出しで作成されるtimer idを使ってclearIntervalを実行します。
仕組みはこれだけ。単純です。

CountdownExec

image.png

Local Variable CountdownSecを-1するだけです。超絶単純です。

が、何故わざわざこいつをJavaScriptから呼び出すなどという面倒なことをしているのかというと、JavaScript内でアクセスできるOutSystemsの要素が限定されているためです。変数として扱えるのはInput Parameterとして与えられたもののみで直接Local Variableなどをいじることはできません。
このため、今回は不要ですが処理結果を後続処理で使いたい場合はOutput Parameterに詰めて送ってやる必要があります。

注意点

SetIntervalを実行したままで画面遷移やブラウザを閉じるなどしてスクリーンが失われると、以下のエラーが発生します。

Invalid call of the '#ClientActionName' client action of the '#ScreenName' since the latter is not currently active. This is likely due to a platform's client action being used as an event handler or in a setTimeout function. Consider removing this call by using the 'On Destroy' event of the screen/block or moving your logic to a global client action.

完全な対応策はないようですが、以下のようにForumでは何度も話題に上がっています。
Invalid call of the 'xyz' client action of the 'Screen'. error Log
今回の場合はエラーログの言う通りOnDestroyclearInterval(timerId);を実行してやれば解決!……すればいいのですが、この場合もブラウザやタブを閉じてしまった場合はService Centerにエラーが記録されてしまいます(OnDestroyは画面遷移の最後に発生するイベントなので)。こちらの対応策としてはJavaScriptのbeforeUnloadイベントなどが考えられますが、これも完全な対応策とは言い切れません。現状は無視するしか方法はないのかな、と思います。

ちなみに、これに一時停止/再開機能を付けようとすると割とかなり相当めんどくさいと思われます。悪しからずご了承ください。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2