処理後にスピナーが起動してしまう

お世話になっております。

現在、サブテーブルを活用した自動反映機能を実装しており、処理に時間を要するためスピナーを設定しようと試みております。

下記のような処理構成にしたときに、スピナーが起動せず、「スピナー非表示」をコメントアウトした場合には処理完了後にスピナーが起動している事が判明しました。(おそらく処理後にスピナー起動・スピナー非表示が一瞬で処理されているのではないかと考えています…)

実現したいのはボタン処理でのスピナー機能ですが、ボタン処理でない場合でも同様の事象が確認できています。また、console上でのエラーはありません。

spin.jsとjQueryはCybozu CDNをもとに設定しております。

以上、解決策があればご教授いただければ幸いです。また、上記以外の原因である場合も同様にご指摘いただければと存じます。

 

jQuery.noConflict();
(function ($) {
"use strict";

     function showSpinner() {
        // 要素作成等初期化処理
        if ($('.kintone-spinner').length == 0) {
          // スピナー設置用要素と背景要素の作成
          var spin_div = $('<div id ="kintone-spin" class="kintone-spinner"></div>');
          var spin_bg_div = $('<div id ="kintone-spin-bg" class="kintone-spinner"></div>');
          // スピナー用要素をbodyにappend
          $(document.body).append(spin_div, spin_bg_div);
          // スピナー動作に伴うスタイル設定
          $(spin_div).css({
            'position': 'fixed',
            'top': '50%',
            'left': '50%',
            'z-index': '510',
            'background-color': '#fff',
            'padding': '26px',
            '-moz-border-radius': '4px',
            '-webkit-border-radius': '4px',
            'border-radius': '4px'
          });
          $(spin_bg_div).css({
            'position': 'fixed',
            'top': '0px',
            'z-index': '500',
            'width': '100%',
            'height': '200%',
            'background-color': '#000',
            'opacity': '0.5',
            'filter': 'alpha(opacity=50)',
            '-ms-filter': "alpha(opacity=50)"
          });
          // スピナーに対するオプション設定
              var opts = {
            'color': '#000'
          };
            // スピナーを作動
          new Spinner(opts).spin(document.getElementById('kintone-spin'));
          console.log('スピナー作成完了');
          
        }
    }

    // スピナーを起動させる関数
    function showSpinnerStart() {
        // スピナー開始(表示)
        $('.kintone-spinner').show();
    }
    
    // スピナーを停止させる関数
    function hideSpinner() {
        // スピナー停止(非表示)
        $('.kintone-spinner').hide();
    }
 
    kintone.events.on(["app.record.create.show", "app.record.edit.show"], function(e) {
      
        //ボタンを設置
        const addSpace1 = kintone.app.record.getSpaceElement('addSpace1');
        const addButton1 =  document.createElement('button');
        addButton1.innerHTML = 'ボタン';
        
        //ボタン押下処理
        addButton1.onclick  = (e) => {

            // スピナー始動(表示)
            showSpinner();
            
            //////////////////////
            //////////////////////
            // 自動反映処理(時間のかかる処理)
            //////////////////////
            //////////////////////
            
            hideSpinner(); // スピナー非表示
            return e;
            
        };
        
        addSpace1.appendChild(addButton1);
        return e;
    });
})(jQuery);

こちらを参考にされると良いかと思います。

https://developer.cybozu.io/hc/ja/articles/204528874

showSpinner() 関数に違いがあるような気がします。

Kazuhiro Yoshidaさん

コメントありがとうございます。
申し訳ございません。上記リンクのページを参考に作成していましたが、色々と試行錯誤しているうちにコードに違いが生じてしまっておりました。

サンプルに沿って改めて書き換え、処理の部分をスリープと置き換えて試してみたものの、やはりスピナー起動は処理後に行われているように感じています。(処理終了のログと同時に起動される)

何かわかることが御座いましたらご教授頂けますと幸いです。

<下記のコードの場合>
何も起こらない(処理終了時にスピナー始動と非表示が同時に作動?)

<スピナー非表示をコメントアウトした場合>
処理終了と同時にスピナーが起動する

 

(function() {
    "use strict";

/**
 * スピナー設置用の関数
 **/

    // スピナーを動作させる関数
    function showSpinner() {
        // 要素作成等初期化処理
        if ($('.kintone-spinner').length == 0) {
            // スピナー設置用要素と背景要素の作成
            var spin_div = $('<div id ="kintone-spin" class="kintone-spinner"></div>');
            var spin_bg_div = $('<div id ="kintone-spin-bg" class="kintone-spinner"></div>');
    
            // スピナー用要素をbodyにappend
            $(document.body).append(spin_div, spin_bg_div);
    
            // スピナー動作に伴うスタイル設定
            $(spin_div).css({
                'position': 'fixed',
                'top': '50%',
                'left': '50%',
                'z-index': '510',
                'background-color': '#fff',
                'padding': '26px',
                '-moz-border-radius': '4px',
                '-webkit-border-radius': '4px',
                'border-radius': '4px'
            });
    
            $(spin_bg_div).css({
                'position': 'fixed',
                'top': '0px',
                'left': '0px',
                'z-index': '500',
                'width': '100%',
                'height': '200%',
                'background-color': '#000',
                'opacity': '0.5',
                'filter': 'alpha(opacity=50)',
                '-ms-filter': "alpha(opacity=50)"
            });
    
            // スピナーに対するオプション設定
            var opts = {
                'color': '#000'
            };
    
            // スピナーを作動
            new Spinner(opts).spin(document.getElementById('kintone-spin'));
        }
    
        // スピナー始動(表示)
        $('.kintone-spinner').show();
    }
    
    // スピナーを停止させる関数
    function hideSpinner() {
        // スピナー停止(非表示)
        $('.kintone-spinner').hide();
    }
    
 
    kintone.events.on(["app.record.create.show", "app.record.edit.show"], function(e) {
      
        //ボタンを設置
        const addSpace1 = kintone.app.record.getSpaceElement('addSpace1');
        const addButton1 =  document.createElement('button');
        addButton1.innerHTML = 'ボタン';
        
        //ボタン押下処理
        addButton1.onclick  = (e) => {

        // スピナー始動(表示)
        showSpinner();
        
        // 5秒スリープさせる
        const d1 = new Date();
        while (true) {
          const d2 = new Date();
        if (d2 - d1 > 5000) {
            break;
          }
        }
        
        // スピナー非表示
        hideSpinner(); 
        
        console.log('処理終了');
        return e;
        };
        addSpace1.appendChild(addButton1);
        return e;
    });
})();

こんにちは。

https://developer.cybozu.io/hc/ja/articles/204528874
参考にされたコードでは、showSpinner()の、後の処理の中で
hideSpinner()が呼ばれているようです。

(function() {
    “use strict”;

    // 一覧ページ
    kintone.events.on(‘app.record.index.show’, function(event) {
        // 現在の検索条件&処理中のレコード取得
        showSpinner(); // スピナー表示
        (new KintoneRecordManager).getProcessingRecords(function(records) {
            kintone.app.getHeaderMenuSpaceElement().innerHTML = ‘処理中のレコード件数:’ + records.length;
            hideSpinner(); // スピナー非表示
        });
    });
})();

JavaScriptは非同期で動作するために、TKさんの記述の通り

<下記のコードの場合>
何も起こらない(処理終了時にスピナー始動と非表示が同時に作動?)

<スピナー非表示をコメントアウトした場合>
処理終了と同時にスピナーが起動する

このような動作になっている気がします。

Promiseまたは、async,awaitを利用して書き換えることで、意図した順番で動作するかと思います。

下記が参考になるかと思います。

https://developer.cybozu.io/hc/ja/articles/360023047852-kintone%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8BPromise%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%AE%E5%9F%BA%E6%9C%AC

私もプログラマーではないので、どのように書けば良いかは分かりません。

上手く行きましたら共有いただけると助かります。

Kazuhiro Yoshidaさん

再度返信いただきまして、ありがとうございます。

ご指摘の通り、非同期で動作してしまっていることが原因のようで、Promiseを使用して同期処理内でスピナー機能を記述することにより意図したタイミングでスピナーが表示されました。

大変助かりました。心からお詫び申し上げます。

また、共有までに修正部分を下記に記載しておきます。

※抜粋

kintone.events.on(["app.record.create.show", "app.record.edit.show"], function(e) {
      
    //ボタンを設置
    const addSpace1 = kintone.app.record.getSpaceElement('addSpace1');
    const addButton1 =  document.createElement('button');
    addButton1.innerHTML = 'ボタン';
    
    //ボタン押下処理
    addButton1.onclick  = (e) => {

        // スピナー始動(表示)
        showSpinner();
        console.log("スピナー始動");
        
        // get処理(REST APIをPromiseにて同期処理実行)
        return kintone.api(kintone.api.url('/k/v1/record', true), 'GET', {app: 1, id: 1}).then(function(resp) {
          const record = resp.record;
            
            // 5秒スリープさせる(処理が短すぎて目視確認できないため)
            const d1 = new Date();
            while (true) {
              const d2 = new Date();
              if (d2 - d1 > 5000) {
                break;
              }
            }
            
            // データを取得してログに出力
          const title = record['タイトル'].value;
            console.log(title);
            
            // スピナー非表示
            hideSpinner();
            console.log('処理終了');
          return e;
        }).catch(function(error) {
            // エラー表示をする
            alert('REST APIでエラーが発生しました。');
          return e;
        });
    };
    addSpace1.appendChild(addButton1);
  return e;
});