サブテーブルのソート

kintoneで商談管理を行っている者ですが、ユーザからの強い要望として、商談履歴(サブテーブル)を日付順にソートできないかとの照会が多いです。

サブテーブルは、コンタクト日、種別、コンタクト内容等々の項目から構成されており、情報が蓄積されていくにつれて、最新情報を読む際にスクロールを多く必要としており、煩わしい状態になっています。

ソートが難しければ、サブテーブルの一番下にジャンプするというようなカスタマイズもありかと思いますが、何かお知恵をお借りしたく、お願いします。

平林 宏章
cstapの落合です。

テーブルのソートですが、以下は価格(price)をキーにソートするJavaScriptです。
sortTable()を日時に対応したものに変更すれば、ご希望の機能は実現できるかと思います。

(function() {
“use strict”;

/**
 * テーブルのソート(数値の場合のみ)
 * 
 * @param Array table ex. event.record.Table.value
 * @param string orderBy フィールド名
 * @param boolean isDesc ASC(false) or DESC(true)
 * @returns Array
 */
var sortTable = function(table, orderBy, isDesc) {
    console.log(table);
    table.sort(function(a, b) {
        var v1 = parseFloat(a.value[orderBy].value);
        var v2 = parseFloat(b.value[orderBy].value);
        var pos = isDesc ? -1 : 1;
        if (v1 > v2) {
            return pos;
        }
        if (v1 < v2) {
            return pos * -1;
        }
    });
    console.log(table);

    return table;
};

// 登録、編集時の処理
kintone.events.on(["app.record.edit.submit", "app.record.create.submit"], function(event) {
    var table = event.record.Table;
    sortTable(table.value, 'price', true);

    return event;
});

})();

以上、参考になりますでしょうか?

平林 宏章

すいません。デバッグ用のコードが残ってました。
console.log(table);は無視してください。

落合様、早速、サンプルをご提示頂き、ありがとうございました。
試してみて、またわからないことが出てきましたら、ご質問させて頂きます。

試してみたのですが、うまくいきませんでした。
kintone側の設定との関係をよく理解できていないため、初歩的な質問かと
思いますが、教えてください。

まず、sortTableのfunction内の記述ですが、
一つ目のパラメータは、対象とするサブテーブルのフィールドコード
二つ目のパラメータは、対象とする項目のフィールドコード
を指定するということで良いでしょうか?

また、レコード表示時にソートを可能とする場合は、kintone.events.onに
app.record.detail.showを記載すれば良いでしょうか?

申し訳ありませんが、よろしくお願いします。

ちなみに、ソート対象としているサブテーブルのフィールドコードはsubtable
ソート項目の日付のフィールドコードはcontact_dateとしています。

平林 宏章様

もう少し汎用的なものにしてみました!

(function() {
“use strict”;

/**
 * テーブルのソート
 * 
 * @param Array table value(ex. event.record.Table.value)
 * @param string orderBy フィールドコード(price)
 * @param boolean isDesc ASC(false) or DESC(true)
 */
var sortTable = function(table, orderBy, isDesc) {
    table.sort(function(a, b) {
        var fieldType = a.value[orderBy].type;
        var v1 = a.value[orderBy].value;
        var v2 = b.value[orderBy].value;

        // 数値と日時は変換してから比較
        switch (fieldType) {
            case 'RECORD_NUMBER':
            case 'NUMBER':
                var v1 = parseFloat(v1);
                var v2 = parseFloat(v2);
                break;
            case 'DATE':
            case 'TIME':
            case 'DATETIME':
            case 'CREATED_TIME':
            case 'UPDATED_TIME':
                var v1 = (new Date(v1)).getTime();
                var v2 = (new Date(v2)).getTime();
                break;
        };

        var pos = isDesc ? -1 : 1;
        if (v1 > v2) {
            return pos;
        }
        if (v1 < v2) {
            return pos * -1;
        }
    });
};

// 登録、編集時の処理
kintone.events.on(["app.record.edit.submit", "app.record.create.submit"], function(event) {
    var table = event.record.subtable.value;
    sortTable(table, 'contact_date', true);

    return event;
});

})();

sortTableの第1引数はテーブルのデータを渡します。
テーブルのデータの取得方法は、平林様の場合ですとevent.record.subtable.valueです。

第2引数はキーとなるフィールドのフィールドコードを渡します。
フィールドコードは、平林様の場合ですと’contact_date’となります。

sortTableがどんな処理をしているか簡単に述べますと
・JavaScriptのArray.sortで並び替え
・数値は、文字列でvalueに入っているのでfloatにキャストする
・日付/時間/日時は、timeに変換
・昇順(ASC)、降順(DESC)の切り替え
といった感じです。

あとは、sortTableを拡張すればさまざまな場合にも使えるようになるかと思います。

以上、参考になりますでしょうか?

落合様、早々にありがとうございました。
以下、頂いたサンプルを元に次のように修正してみました。

(function() {
“use strict”;
/**
* テーブルのソート
*
* @param Array table value(ex. event.record.Table.value)
* @param string orderBy フィールドコード(price)
* @param boolean isDesc ASC(false) or DESC(true)
*/

Array table value(event.record.subtable.value)
string orderBy (contact_date)
boolean isDesc ASC(false) or DESC(true)

var sortTable = function(table, orderBy, isDesc) {
table.sort(function(a, b) {
var fieldType = a.value[orderBy].type;
var v1 = a.value[orderBy].value;
var v2 = b.value[orderBy].value;

// 数値と日時は変換してから比較
    switch (fieldType) {
        case 'RECORD_NUMBER':
        case 'NUMBER':
            var v1 = parseFloat(v1);
            var v2 = parseFloat(v2);
            break;
        case 'DATE':
        case 'TIME':
        case 'DATETIME':
        case 'CREATED_TIME':
        case 'UPDATED_TIME':
            var v1 = (new Date(v1)).getTime();
            var v2 = (new Date(v2)).getTime();
            break;
    };

    var pos = isDesc ? -1 : 1;
    if (v1 > v2) {
        return pos;
    }
    if (v1 < v2) {
        return pos * -1;
    }
});

};

// 登録、編集時の処理
kintone.events.on([“app.record.edit.submit”, “app.record.create.submit”], function(event) {
var table = event.record.subtable.value;
sortTable(table, ‘contact_date’, true);

return event;

});

})();

よく理解できていないので、これで合っているのか不安です。

また、表タイトルにクリック時のアクションを埋め込むためには、
更に表示のためのスクリプトが必要ということになりますか?
何から何までお恥ずかしい限りですが、お教えください。

ソースの11行目からの以下の部分はいりません。
これだとエラーが起きるかと思います。

Array table value(event.record.subtable.value)
string orderBy (contact_date)
boolean isDesc ASC(false) or DESC(true)

前回お渡ししたサンプルを修正せずにそのまま利用しても動くかと思います。

ちなみにソースのどの部分が理解できないのでしょうか?

また、「表タイトルにクリック時のアクション」というのは、kintoneのアクション機能のことではなく、JavaScriptのイベントという意味で良かったでしょうか?

kintoneで用意されているイベントは、kintone APIのJavaScript API(イベント)で確認できます。
また、自分でボタンを設置してイベント処理を行うこともできます。
これについては、Tipsの「はじめよう kintone JavaScript API」シリーズを参考にしてください。

落合様、大変お手数をおかけしました。
余計の修正を入れたのが、間違いでした。
頂いたサンプルをそのまま適用することで、日付の降順にソートして、
保存されるようになりました。
お忙しい中、本当にありがとうございました。助かりました。

ちなみに、アクションと言った件ですが、本件の最初の照会の仕方が
悪かったのですが、出来上がりのイメージとしては閲覧画面で、
表タイトルの日付をクリックすることで、動的にテーブルを降順、昇順に
ソートするイメージを持っていたためです。
これの対応方法も何か参考になる情報がありましたら、お教えください。

動いたようで良かったです!

レコード詳細画面で動的にソートしたいということですが、以外に難しいかと思います。
kintone.app.record.setが詳細画面に対応していると簡単なのですが、追加・編集画面でしか利用できないので使えないですし。。。

無理やりやるとすれば、DOMを自分で変更することになるかと思います。
ただし、これはバージョンアップなどで動かなくなる可能性があり、あまりお勧めできません。

落合様、やはり動的は難しいですか。
cybozu社には、かなり前から要望しているのですが、なかなか
バージョンアップされないところからも難易度が高いと想定していました。

サブテーブルのハンドリングは、難しいですね。

なお、実務上では、今回作成頂いたスクリプトで十分対応できるので、
早速採用させて頂きます。

いろいろとありがとうございました。

落合様

本件につきましては、色々とありがとうございました。
jsを適用して運用を開始したのですが、次の不具合が見つかったため、
現在適用を外しました。
何か対策がありましたら、お教え頂きたくお願いします。

【現象】
・並び替え時にルックアップフィールド項目のみ並び替え対象外となる
(例)
日付 報告内容 面談者(ルックアップフィールド)
2014-7-1 デモしました AAAA
2014-7-5 成約しました BBBB
↓(保存後)
2014-7-5 成約しました AAAA
2014-7-1 デモしました BBBB

※上記のように日付と内容は並び替えされるが、面談者のみ
並び替え前の行に残ってしまう。

平林 宏章様

【現象】
・並び替え時にルックアップフィールド項目のみ並び替え対象外となる

これは、kintoneの仕様だったような記憶があります。
ルックアップを利用するなら、サブテーブルの並び替えは難しいかと思います。

回避策としては以下のような方法はどうでしょうか?

■アプリの設定
・面談者を表示用の文字列フィールドと編集用のルックアップフィールドを分ける

■JavaScriptの制御
・表示時には、編集用のフィールドは表示しない
(kintone.app.record.setFieldShownが確かテーブル内フィールドに対応してなかったので、無理やりになるかもしれません)
・登録/編集時には表示用のフィールドは表示しないor編集不可にする
()
・登録/編集画面表示イベントで、編集用フィールドに表示用フィールドの値を入れ、ルックアップの取得を行う
(参考:https://cybozudev.zendesk.com/hc/ja/articles/201941984#step8)
・登録/編集の実行前イベントで、編集用フィールドの情報を表示用フィールドにコピーする

以上、参考になりますでしょうか?

落合様

ご回答ありがとうございます。
私も再度の質問をした後に、調べましたが、ルックアップフィールド項目の
ハンドリングは難しいことがわかりました。
(確かに、RESTapi

落合様

ご回答ありがとうございます。

私も再度の質問をした後に、調べましたが、ルックアップフィールド項目の
ハンドリングは難しいことがわかりました。
参照元へのリンク情報を保持しているでしょうから、api上での更新は
難しいと想定しています。
(確か、インポート時もルックアップフィールドは対象外だったかと)

頂いたアイデアは、大変参考になります。
ただ、テーブル上の表示/非表示をどう実現するのかが問題です。
試しに、kintone.app.record.setFieldShownでテーブル上の
項目の非表示をテストしてみましたが、表示されてしまいました。
「無理やり」対応する方法って、何かアイデアありますか?

なお、今のところ、文字列フィールドを新たに追加してから、
一旦現在のデータをダウンロード後、改めて、追加した
文字列フィールドにアップロードしてから、元の項目を削除しようかと
思っています。

平林 宏章様

無理やりテーブルの項目を非表示にする方法は、以下のようにclass名に対して直に処理を行う方法です。なお、要素の取得にはjQueryを利用しています。

// ルックアップフィールドを非表示にする
kintone.events.on(["app.record.edit.show", "app.record.create.show"], function(event) {
    $('.label-139959').hide();
    $('.field-139959').parent('td').hide();

    return event;
});

これは、DOMに依存するためバージョンアップなどで動かなくなる可能性がありますが、実処理に影響のあるものではないので、動かなくなっても影響は少ないでしょう。

以上、参考になりますでしょうか?

落合様

ご回答ありがとうございます。
大変参考になります。
色々と試行してみます。
どうしてもうまくいかなければ、最後の手段として先ほど記載したように、
レコードの一括コピーを行って、ルックアップフィールドをなくす対応で
今回は逃げようと思っています。

平林 宏章様
また、何かありましたらお気軽にご質問ください!

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。