(第4回)Electronでクロスプラットフォーム開発しよう(製造編③)

(第4回)Electronでクロスプラットフォーム開発しよう(製造編③)

目次

はじめに
NeDB
NeDBの基本的な使い方
DBへの保存
保存データの表示
次回予告

はじめに

前回は、jKanbanを使用してかんばんアプリの画面を作成しました。
今回は、タスクの保存と保存データの表示を行います。

NeDB

今回はタスクを保存して、次回起動時に保存したタスクが表示されるようにしたいので、NeDBを使用します。
NeDBはJavaScriptで動作する組み込み用のデータベースで、別途DB用ライブラリが不要でJavaScriptを実行できる環境であれば動作します。
NeDB:https://github.com/louischatriot/nedb

※NeDBは2015年からメンテナンスが行われていませんので注意してください。

まずは、 NeDBを使用するためにnpm installで必要なパッケージをインストールします。

npm install nedb

パッケージのインストールが完了したら、実際にDBを利用できるようにします。
NeDBではインメモリとDBファイルの2パターンの利用方法があります。
今回は、ツールを再起動してもデータを保持する必要があるので、ファイル形式でDBを用意します。
下記のコードをメイン画面(index.html)に追加することで、実行ファイルと同階層にdataフォルダを作成し、kanban.nedbというファイルが自動で作成されます。

const db = new Datastore({ filename: 'kanban.nedb', autoload: true })

NeDBの基本的な使い方

NeDBのAPIはMongoDBのAPIのサブセットなので、MongoDBと同じ使い方ができます。

追加

db.insert(doc)
db.insert(doc, (error, newDoc) => {})

ドキュメントを追加する場合は、insertを使います。
doc 追加するドキュメント。オブジェクトを指定します
newDoc DB登録後のドキュメントでアルファベット16文字からなる_idフィールドが追加されています

更新

db.update(query, doc, option, (error, numOfDocs) =>{});

ドキュメントを更新する場合は、updateを使います。
query 更新対象のドキュメントを指定  正規表現によって部分一致なども可能
    例 IDを指定して検索する場合はvar query = {_id:”xxxxxxxxxxxxxxxx”}  のようにします
doc 更新するドキュメント insertと同様にオブジェクトを指定する
option 複数ドキュメントの更新、一致するものがない場合に更新などで利用 今回は使用しません
numOfDocs 更新したドキュメント件数が返ってきます

削除

db.remove(query, options, (error, numOfDocs) => {})

ドキュメントを更新する場合は、removeを使います。
query 削除対象のドキュメントを指定
options 複数削除で利用
numOfDocs 更新したドキュメント件数が返ってきます

query 削除対象のドキュメントを指定
options 複数削除で利用
numOfDocs 更新したドキュメント件数が返ってきます

検索

db.find(query, (error, docs){})
db.findOne(query, (error, doc){})

ドキュメントを検索する場合は、findまたはfindOneを使います。
find クエリに一致するドキュメントを返す
query 検索対象ドキュメントを指定   正規表現によって部分一致なども可能
    例 IDを指定して検索する場合はvar query = {_id:”xxxxxxxxxxxxxxxx”}  のようにします
findOne クエリに一致したドキュメントのうち、1つを返す

DBへの保存

NeDBが使えるようになったので、kanban操作時にデータをNeDBへ保存するようにします。
まず、jKanbanから保存用のオブジェクトを取得する関数を用意します。

// kanbanからdb登録用オブジェクトを生成する
function getBoardItem(boardid) {
    var target = kanban.getBoardElements(boardid);// kanbanから指定したボードIDのエレメントを取得
    var items = Array.from(target).map(x => ({ title: x.textContent }));// 取得したエレメントをオブジェクトに変換
    // DB登録用オブジェクトを作成
    var board = {
        boardid: boardid,
        item: items
    }
    return board;
}

次に、取得したオブジェクトをDBに保存するメソッドを用意します。

function saveBoard() {
    for (var i = 1; i <= 4; i++) {//ボード数分のループ
        var boardid = `board-${i}`;
        var query = { 'boardid': boardid };
        var board = getBoardItem(boardid);// DB登録用オブジェクトをkanbanから取得
        var options = { upsert: true };// queryの対象が存在しなければ更新ではなく追加
        db.update(query, board, options, function (err, numOfDocs) {
            console.log(board, numOfDocs);
        });
    }
}

先ほど紹介したdb.updateを使ってkanbanオブジェクトをDBに登録します。
optionupsertを使用しているので、追加・更新を1文で行うことができています。

次に、kanban操作時にデータを保存したいので、kanbanの各イベント処理で上記のsaveBoardを呼び出します。

        var kanban = new jKanban({
            element: "#kanban",     //ボード表示対象の要素
            gutter: '5px',         //ボード同士の間隔
            widthBoard: '250px',    //ボードのサイズ
            boards: boards,         //初期データ
            dragBoards: false,       //ボードのドラッグ
            itemAddOptions: {       //タスク追加用のボタンを表示
                enabled: true,                                      // 追加ボタン表示
                content: '+',                                       // ボタンテキスト
                class: 'kanban-title-button btn btn-light btn-sm',  // ボタンに設定するclass
                footer: false                                       // 表示位置
            },
            click: function (el) {

            },
            buttonClick: function (el, boardId) {
                // 入力フォームを作成してボードに追加
                const formItem = document.createElement('form');
                formItem.innerHTML = '<input type="text" class="form-control" placeholder="課題を入力...">'
                formItem.innerHTML += '<button type="submit" class="btn btn-primary btn-sm">追加</button>'
                formItem.innerHTML += '<button type="button" class="btn btn-secondary btn-sm">キャンセル</button>';
                kanban.addForm(boardId, formItem);

                //キャンセルボタン
                formItem.elements[2].addEventListener("click", (e) => {
                    formItem.parentNode.removeChild(formItem); //入力フォーム削除
                });
                //タスク追加処理
                formItem.addEventListener('submit', (e) => {
                    e.preventDefault();
                    var title = e.target[0].value;
                    // 0文字の場合登録しない
                    if (title.length == 0) {
                        return;
                    }
                    var elem = kanban.addElement(boardId, { "title": title }); //入力された文字列をタスクとして登録
                    formItem.parentNode.removeChild(formItem); //入力フォーム削除
                    saveBoard();
                })
            },
            dropEl: function (el, target, souce, sibling) {
                saveBoard();
            }
        });

前回はbuttonClickイベントのみ使用しましたが、タスクを別のボードに移動させた際もDBを更新したいので、dropElイベントを追加して、そちらでもsaveBoard()を呼び出します。

ここまでの処理で、かんばんへのタスク追加、ボード移動の内容がDBに反映されるようになりました。kanban.nedbファイルを開くと、オブジェクトがテキストとして保存されているのが確認できます。

保存データの表示

ここまでで保存はできましたが、ツールを起動するたびにかんばんが初期状態に戻ってしまうので、画面起動時に保存されたデータを画面へ反映するようにします。

        function loadDB() {
            db.find({ boardid: /^board/ }, function (err, docs) {
                docs.forEach((doc) => {
                    doc.item.forEach((item) => {
                        kanban.addElement(doc.boardid, item); //入力された文字列をタスクとして登録
                    });
                });
            });
        }

DBに保存されたデータから、”boardid”が”board”で始まるデータを取得し、取得したデータをかんばんへ追加するメソッドを用意します。
このメソッドをjKanbanの初期化後に呼び出すことで、起動するたびに前回操作していた内容が表示されることが、確認できます。

次回予告

今回は、タスクの保存と保存データの表示を作成しました。
かんばんアプリとして最低限の機能はできましたが、不要なメニューが表示されていたり、ウィンドウサイズが適していないので、次回はそのあたりの対応を進めてみたいと思います。