コンテンツへスキップ

インジケータを出して誤操作防止。hifiveなら簡単にできます!

by : 2014/07/14

Ajaxを使った保存処理の最中やデータレンダリング中など、処理中には誤ったボタン操作やクリックを防止したいと思うことがあるでしょう。そんな時に役立つのがインジケータです。

hifiveでは高機能なインジケータクラス(Indicator)が備わっています。Indicatorを使いこなせばユーザビリティの高いシステム構築に役立つはずです。

処理はコントローラの中で行う

例えばボタンを押された時にインジケータを出したいとします。こちらは押す前です。


押すとインジケータ表示になります。


コードは次のようになります。

'#button click': function(context) {
  var indicator = this.indicator({
    message: '処理中…'
  }).show();
  // 非同期処理の中で使用するために退避
  var dfd = this.deferred();
  setTimeout(function() {
    indicator.hide();
    dfd.resolve();
  }, 800);
  return dfd.promise();
},

この手のインジケータを出す処理というのは、非同期処理が多いでしょう。非同期処理のはじまる前にdeferredを定義し、最初にpromiseを返します。その上で非同期処理の完了時にreslveを返すのがコツです。上記のコードの場合、800ms処理を遅延しています。indicatorもhideメソッドで消えます。

対象を変更できる

先ほどの例ではコントローラの監視対象になっているDOM内が処理対象になっていました。次の例では親要素まで含めて操作不可にします。


このボタンをクリックします。


このように parent と書かれたDOMもインジケータ対象になります。

コードは次のようになります。

'#parentBlock click': function(promise, resolve, reject) {
  var indicator = this.indicator({
    // targetに親コントローラを指定
    target: $(this.rootElement).parent(),
    message: 'child2 parent block'
  }).show();
  var dfd = this.deferred();
  setTimeout(function() {
    indicator.hide();
    dfd.resolve();
  }, 800);
  return dfd.promise();
},

先ほどとの違いはインジケータを作る際のオプションtargetを指定していることです。parent()として親要素を指定しています。このようにインジケータで処理できない領域を指定するのは柔軟に変更できるのが特徴です。

子のコントローライベントを使う

さらに別な例です。以下を見てください。


3つのDOMがあります。この一番親に当たるDOMのボタンをクリックします。


そうするとこのように子のDOMに設定されているインジケータが実行されます。

処理としてはまず親のコントローラに次のように記述します。

'#childrenBlock click': function() {
  this.$find('#child3Block').trigger('selfBlock');
  this.$find('#child4Block').trigger('click');
},

上の方は selfBlock という独自イベントを呼び出しています。下の方はクリックです。まず上の行の処理は次のコードが呼び出されます。

// トリガーで呼ばれるイベント
'#child3Block selfBlock': function(context) {
  // 自身をブロックする
  var indicator = this.indicator({
    message: 'child1 self block'
  }).show();
  // 非同期処理の中で使用するために退避
  var dfd = this.deferred();
  setTimeout(function() {
    // 自身のブロックを解除
    indicator.hide();
    dfd.resolve();
  }, 800);
  return dfd.promise();
},

さらに下の行も同様です。

'#child4Block click': function(context) {
  // 自身をブロックする
  var indicator = this.indicator({
    message: 'child1 self block'
  }).show();
  // 非同期処理の中で使用するために退避
  var dfd = this.deferred();
  setTimeout(function() {
    // 自身のブロックを解除
    indicator.hide();
    dfd.resolve();
  }, 800);
  return dfd.promise();
},

この二つの処理の違いは、上は独自のイベント、下はクリックイベントということです。そのため、下の方のDOMにあるボタンを押すと、その部分だけインジケータが表示されます。


インジケータ表示部分を細かく制御したり、使い回すのも簡単にできます。

ウィンドウ全体をブロック

インジケータを表示するような処理を行っている場合、ウィンドウ全体を触れないようにしたいと思うかも知れません。そのような対応も可能です。


処理は次のようになります。

'#globalBlock click': function(promise, resolve, reject) {
  var dfd = this.deferred();
  // BODYをブロックする
  var indicator = this.indicator({
    target: document.body,
    message: 'global block',
    promises: dfd.promise()
  }).show();
  // indicator()にpromiseオブジェクトを渡しているのでresolve()またはreject()されると自動的にindicator.hide()される
  setTimeout(function() {
    dfd.resolve();
  }, 2000);
  return dfd.promise();
}

方法としては簡単で、targetオプションにdocument.bodyを渡しています。さらにpromisesオプションにpromiseを渡すことで、resolveやrejectを行うと自動的にインジケータを非表示にしてくれる機能もあります。

プログレス表示

処理中をより効果的に知らせるためにプログレス表示もできます。次の画像の数字部分です。


コードは次のようになります。

'#child6Start click': function(context) {
  // インジケータの表示
  var indicator = this.indicator({}).show();
  // Deferredオブジェクトを作成
  var dfd = this.deferred();
  var i = 0;
  var id = setInterval(function() {
    // プログレスバーの非表示
    if (i >= 100) {
      indicator.hide();
      clearInterval(id);
      dfd.resolve();
      return;
    }
    // 進捗状況(%)の表示
    indicator.percent(i++);
  }, 70);
  return dfd.promise();
}

こちらの例ではsetIntervalを使って定期的に処理を回して、 indicator.percent(i++); を実行しています。これで数字部分の表示がアップデートしていく仕組みです。

promiseが複数ある場合

最後に一番複雑なパターン、promiseが複数ある場合です。Ajaxを複数並列で処理するといった場合はよくあります。そういった場合に使えるテクニックです。

'#child8Start click': function(context) {
  var that = this;
  // 4秒掛かる処理
  var func1 = function() {
    var df1 = that.deferred();
    setTimeout(function() {
      df1.resolve();
    }, 4000);
    return df1.promise();
  };
  // 6秒掛かる処理
  var func2 = function() {
    var df2 = that.deferred();
    setTimeout(function() {
      df2.resolve();
    }, 6000);
    return df2.promise();
  };
  // func1とfunc2が終わるのを待つので、6秒待つことになる。
  var indicator = this.indicator({
    promises: [func1(), func2()]
  }).show().message('処理中...');
}

見ての通り、インジケータのpromisesオプションは複数のpromiseを指定できるようになっています。この部分は全てのpromiseがresolveまたはrejectになるまで待ちますので、最も長いfunc2の6秒待ってからインジケータが非表示になる仕組みです。

なおこれらの処理は h5.css を読み込んでいる必要があります。.h5-indicatorにスタイル設定がしてありますのでシンプルで効果的なインジケータ表示が簡単にできるようになっています。

今回紹介したコード、画面はhifive Block Sampleに掲載されていますのでぜひ参考にしてください。


いかがだったでしょうか。処理待ちというのはよくありがちですが、JavaScriptでは非同期処理が多いのでユーザが操作を急いでしまってデータに不備が生じるケースが多々あります。そういった問題を未然に防げるインジケータ、ぜひ活用してください。

hifive – HTML5企業Webシステムのための開発プラットフォーム – hifive

HTML5企業Webシステムのための開発プラットフォーム

From → hifive

コメントは受け付けていません。

%d人のブロガーが「いいね」をつけました。