新規投稿
フォローする

WebSocketを使って一覧をリアルタイム更新

レコードが追加・編集されたら一覧を自動更新して欲しいという要望は多いのではないかと思います. 今回は,WebSocketを使って一覧をリアルタイム更新するサンプルを紹介します.

デモ

レコードが追加・編集されたら,カスタマイズビューをリアルタイム更新します.

今回は,ローカルサーバーでの実装例をご紹介します.
※実務で利用する場合は,公開サーバーを立てる必要があります.

ローカルサーバーの準備

環境

Node.jsが必要です.

作成するファイル

下記ファイルを全て同一ディレクトリに設置します. sample.jsの7行目の「columns」は,ご自身のアプリに合わせて変更が必要です.

・package.json
・index.js
・sample.js
・localhost.pem
・localhost-key.pem

・package.json

{
  "dependencies": {
    "express": "^4.15.2",
    "https": "^1.0.0",
    "socket.io": "^1.7.3"
  },
  "scripts": {
    "start": "node index.js"
  },
  "license": "MIT"
}

・index.js

const app = require('express')();
const https = require('https');
const fs = require('fs');
const ssl_server_key = 'localhost-key.pem';
const ssl_server_crt = 'localhost.pem';
const port = 3000;
const file = 'sample.js';

app.get('/', (req, res) => {
  res.sendFile(`${__dirname}/${file}`);
});
const server = https.createServer({
  key: fs.readFileSync(ssl_server_key),
  cert: fs.readFileSync(ssl_server_crt)
}, app).listen(port);

const io = require('socket.io')(server);
io.on('connection', (socket) => {
  socket.on('add', (record) => {
    io.emit('add', record);
  });
  socket.on('update', (record) => {
    io.emit('update', record);
  });
});

・sample.js
7行目の「columns」は,ご自身のアプリに合わせて変更が必要です.

(function() {
  "use strict";
  var socketUrl = 'https://localhost:3000';
  kintone.events.on([
    'app.record.index.show',
  ], function(event){
    if(event.viewName !== 'リアルタイム更新') return;
    var columns = [ //一覧に表示するフィールドのフィルドコード
      '数値',
      '文字列__1行_',
    ];
    var wrapperId = 'realtime-view';
    var client = new KintoneRestAPIClient();
    var tableManager = new TableManager(columns);
    kintone.Promise.all([
      client.app.getFormFields({app: kintone.app.getId()}).then(function(formFields){
        tableManager.setFormFields(formFields);
      }),
      client.record.getAllRecordsWithCursor({app: kintone.app.getId()}).then(function(records){
        tableManager.setInitialRecords(records);
      }),
    ]).then(function(){
      document.getElementById(wrapperId).appendChild(tableManager.render());
    });
    var socket = io.connect(socketUrl);
    socket.on('add', function(record){
      toastr.info('$id: '+record.$id.value, 'レコードが追加されました.');
      tableManager.addRecord(record);
    });
    socket.on('update', function(record){
      toastr.info('$id: '+record.$id.value, 'レコードが更新されました.');
      tableManager.updateRecord(record);
    });
  });

  kintone.events.on([
    'app.record.create.submit.success',
    'app.record.edit.submit.success',
  ], function(event){
    var type = event.type === 'app.record.create.submit.success' ? 'add' : 'update';
    var socket = io.connect(socketUrl);
    socket.emit(type, event.record);
    return new kintone.Promise(function(resolve){
      socket.on(type, function(){
        resolve();
      });
    });
  });

  var TableManager = (function(columns){
    var TableManager = function(columns){
      this.columns = columns;
      this.table = document.createElement('table');
      this.thead = document.createElement('thead');
      this.tbody = document.createElement('tbody');
      this.table.appendChild(this.thead);
      this.table.appendChild(this.tbody);
    }
    TableManager.prototype = {
      render: function(){
        return this.table;
      },
      setFormFields: function(formFields){
        this.thead.innerHTML = '';
        var tr = document.createElement('tr');
        tr.innerHTML = '<th>$id</th>';
        this.columns.forEach(function(column){
          var th = document.createElement('th');
          th.innerText = formFields.properties[column].label;
          tr.appendChild(th);
        });
        this.thead.appendChild(tr);
      },
      createRowContent: function(record){
        var fragment = document.createDocumentFragment();
        this.columns.forEach(function(column){
          var td = document.createElement('td');
          td.innerText = record[column].value;
          fragment.appendChild(td);
        });
        return fragment;
      },
      createRow: function(record){
        var id = record.$id.value;
        var tr = document.createElement('tr');
        tr.id = 'record-'+id;
        tr.innerHTML = '<td><a href="show#record='+id+'">'+id+'</a></td>';
        tr.appendChild(this.createRowContent(record));
        return tr;
      },
      updateRow: function(record){
        var id = record.$id.value;
        var tr = document.getElementById('record-'+id);
        tr.innerHTML = '<td><a href="show#record='+id+'">'+id+'</a></td>';
        tr.appendChild(this.createRowContent(record));
      },
      setInitialRecords: function(records){
        var _this = this;
        this.tbody.innerHTML = '';
        var fragment = document.createDocumentFragment();
        records.forEach(function(record){
          fragment.appendChild(_this.createRow(record));
        });
        this.tbody.appendChild(fragment);
      },
      addRecord: function(record){
        this.tbody.insertBefore(this.createRow(record), this.tbody.firstChild);
      },
      updateRecord: function(record){
        this.updateRow(record);
      }
    }
    return TableManager;
  })();
})();

・localhost.pem, localhost-key.pem

SSLサーバ証明書ファイルと鍵ファイル. 「https localhost 証明書」などでググると作り方が出てきます.

依存パッケージのインストール

ファイルを設置したディレクトリで下記コマンドを実行します.

npm install

ローカルサーバーの起動

ファイルを設置したディレクトリで下記コマンドを実行します.

npm run start

kintoneの設定

カスタマイズビュー(一覧名: リアルタイム更新)

<div id="realtime-view"></div>

JavaScript

下記ファイルを順に読み込みます.

https://js.cybozu.com/kintone-rest-api-client/1.4.2/KintoneRestAPIClient.min.js
https://js.cybozu.com/jquery/3.5.1/jquery.min.js
https://js.cybozu.com/toastr/2.1.4/toastr.min.js
https://localhost:3000/socket.io/socket.io.js
https://localhost:3000/

CSS

下記ファイルを順に読み込みます.

https://js.cybozu.com/toastr/2.1.4/toastr.min.css
・sample.css

・sample.css

#realtime-view table{
  margin: auto;
}
#realtime-view th,
#realtime-view td{
  border: 1px solid #000;
  padding: 10px;
}
1

0件のコメント

サインインしてコメントを残してください。