kintoneの追加API setFieldShown はテーブルの個別セルに対応していますか?

初めまして。
お客様の環境に導入するために、色々とテストをしながら開発を進めています。

手始めに請求書用アプリを開発しているのですが

★小計、総計に自動計算を使用。
★その為、自動計算の対象に空欄があるとN/Aになってしまう。仕方がないので数量や単価を0としておく。
★cstap社さんのプリントクリエイターを利用予定ですが、上記の様なケースで 0 を非表示にすることは出来ず(裏技的にif文等で条件により非表示ということができれば最高ですが)、N/Aとなる場合はN/Aで印刷されてしまうので、請求書として利用する事に現場からクレームが…。

★過去の投稿にフォームの値変更時のイベント取得の件が話題に上っていましたが、これが簡単にできれば自力でN/Aを回避出来るように計算してしまう手もありますが、現状は少し難しい(後々のこともあるので…)。

★追加APIにテーブルの行削除機能が存在するので、これを利用して要らないテーブル行を削除してみるものの、デフォルト値を0としているとサブミット後にデフォルト値の値で1行復活。デフォルト値を空値しているとレコード詳細画面の計算結果がN/Aに…。

★サブミット時にテーブルの値を操作できるようなったようなので、小計0の時に印刷したくない項目に対してダミーのフォームを追加。サブミット時に状態をチェックして空欄にしたり、小計の値をコピーして、印刷の時にはこちらのダミーの値を使用することで、空っぽの時には何も印刷されていないように見せかけることにしました。

☆今回、項目をhiddenにするAPIも追加されたようですが、これはテーブル各行の特定セルを指定することは可能でしょうか。

例)kintone.app.record.setFieldShown(‘文字列__1行’, false);

テーブル全体は非表示に出来ましたが、セル単体の場合のフィールドコードの表記の仕方がよく分からず悩んでいます。

自動計算については似たようなケースが発生するのではないかと思うのですが、皆さま、どのように回避しているのでしょうか。良いお知恵があればご教授願いたく、よろしくお願いいたします。

Shobu Umemura様
cstapの落合です。

プリントクリエイターの利用予定とのこと、大変ありがとうございます!
サポートの方から話を伺いました。

要件としては以下の2点が主なところでしょうか。
①N/Aを表示させない
②必要項目が記入されている場合は計算

以下のようなkintoneのカスタマイズでどうでしょう?
・計算フィールドではなく数値フィールドを小計と総計に使う
・小計と総計の計算は、JavaScriptで行う
・必要項目が記入されていない場合は、計算しない
・小計と総計のフィールドは、JavaScriptで編集不可にする

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

落合様

お返事ありがとうございます。

計算フィールドの代わりに数値フィールドを使用し、空欄を避けるようにして自力で計算する流れも考えておりました。

この流れで、サブミット時に計算結果を登録することはできました。

実際は、編集中にユーザが各フィールドの値を変更したタイミングでリアルタイムに計算結果を反映させたいので、その方法を模索していたのですが、過去の落合様の投稿にあったように、完成済みフォームのDOMやIDを使って少々強引に実装する方法しか思いつかず、kintone側の何らかの変更に追従できないのではないかと考え、この方は避けたいと考えています。

フィールドの変更イベントが数値フィールドやテキストフィールドには発生しないようなので、トリッキーな方法を採らずにこれを解決する方法があればある程度エレガントに処理できるのですが…。

今の所、前述の投稿のようにダミーのフィールドを用意して、編集や詳細画面中は不使用項目に0などの数値が入る事は目を瞑り、ダミー項目へサブミット時に印刷したい内容を放り込んで使用する方法に至りました。
(テーブル中に存在するダミー項目をhiddenできるとある程度解決なので、CSSで無理矢理消してしまえそうですが…)

引き続きよろしくお願いいたします。

Shobu Umemura様

・編集中にユーザが各フィールドの値を変更したタイミングでリアルタイムに計算結果を反映させたい
この機能の実装が重要なのかと思いました。

サンプルを作ってみたので、よかったら参考にしてください。
ただ、テーブルの行追加イベントがないので、テーブルの行追加時に小計を編集不可にできていないです・・・

/**
* フィールドは全て数値フィールド
*
* テーブル:Table
* 単価:price
* 個数:num
* 小計:sales
*
* 総計:total
*/

(function() {
“use strict”;

function loadJS(src) {
    document.write('<script type="text/javascript" src="' + src + '"></script>');
}
 // jQuery の JavaScript ファイル
 loadJS("https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js");


/**
 * 計算処理
 */
var myCalculate = function(record) {
    var table = record.Table.value;
    var total = 0;
    for (var i = 0, l = table.length; i < l; i++) {
        var row = table[i].value; // テーブルの1行
        // 小計を計算
        var price = row.price.value;
        var num = row.num.value;
        if (price && num) {
            row.sales.value = price * num;
            total += row.sales.value;
        } else {
            row.sales.value = null;
        }
    }
    record.total.value = total;
};

// 編集時に計算するイベント
kintone.events.on(["app.record.edit.show", "app.record.create.show"], function(event) {
    $(document.body).on('change', "input[type='text']", function() {
        var record = kintone.app.record.get();
        myCalculate(record.record);
        kintone.app.record.set(record);
    });
});

// 計算する数値フィールドを編集不可にする
kintone.events.on(["app.record.edit.show", "app.record.create.show"], function(event) {
    var table = event.record.Table.value;
    for (var i = 0, l = table.length; i < l; i++) {
        table[i].value.sales.disabled = true;
    }
    event.record.total.disabled = true;

    return event;
});

// 登録、編集時の処理
kintone.events.on(["app.record.edit.submit", "app.record.create.submit"], function(event) {
    myCalculate(event.record);

    return event;
});

})();

落合様

サンプルコードありがとうございます。大変助かります。

試す前なのですが、

jQuery使ってchangeイベントフックしている部分もテーブルの追加に対応できない部分でしょうか。

お行儀が良くない気もしますが、DOMNodeInsertedとかタイマー使ってテーブルの追加に対応させられるような気もしますね。。。

$(document.body).on(‘change’, “input[type=‘text’]”, function() {

この処理と同じ事を試したのですが(フォームのID等使ってもう少しピンポイントに指定しましたが、ザックリやってしまっても大きな影響なさそうですね)、先々、APIにテキストフォームの変更イベントが実装された際、バッティングするような可能性は無いでしょうか…。なるべく手離れの良い作りにしたいと思っているところですが。。。
kintoneが生成するフォームIDを使用する是非と、APIの処理との兼ね合いが気になってこの方法を避けたのですが、注意すべき点があればご教示頂けると幸いです。

色々とありがとうございます。引き続きよろしくお願いいたします。

Shobu Umemura様

>jQuery使ってchangeイベントフックしている部分もテーブルの追加に対応できない部分でしょうか。
計算処理は追加された行でも行われます。
しかし、小計フィールドが編集可能のままのため、この方法を使う場合は運用者に注意してもらう必要があるかと思います。

$(document.body).on(‘change’, “input[type=‘text’]”, function() {
は、関係ないフィールドが変更された場合でも計算処理が走ります。
そのため、計算回数によって結果が異なるような計算はできないので注意してください。
あまりいい方法ではないですが、手っ取り早く実現できて、問題が起きにくい方法かと思います。

>先々、APIにテキストフォームの変更イベントが実装された際、バッティングするような可能性は無いでしょうか…。
APIにテキストフォームの変更イベントが実装された際に特に問題が起こるというのはないかと思います。
問題が起こるパターンとしては、jQueryで「input[type=‘text’]」を取得できないようなDOMに変更された場合かと思います。
しかし、これはほとんど考えられないので、もし問題が起きた場合はその時修正するというスタンスで問題ないかと思います。

idやclassで指定する方法は、バージョンアップの時に動かなくなる可能性があるので、できれば避けた方がいいかと思います。

落合様

ご助言、感謝いたします。
これで概ね解決できそうです。
数量1の時に1を見せたくないと言った要望もあったのですが、これも解決できそうです。テーブルの各行の特定セルをhiddenにできると、hiddenに組み立てた結果を入れてプリントクリエイターに回すことで、もう少し凝った表現が出来そうですが、この辺は順次、、、ということにしたいと思います。

$(document.body).on(‘change’, “table input[type=‘text’]”, function() {} をOKということにしたので、テーブル行の追加、削除時のイベント処理も強引に入れて実装してまっても良いか…という方向で作業を続ける予定です。

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

度々スミマセン。
少し言葉が足りませんでした。
行の追加削除について、削除の方は行がなくなって値が減った結果を総計に反映する必要があるので、イベントをフックして計算ルーチンを回す必要がありそうです。その為、追加削除もフックできるようにしようとしています。
基本的には解決できたと思いますが、事情により1両日中に完成させる必要があり、間に合うかどうか心配です(/_:wink: ありがとうございました。

Shobu Umemura様
解決できそうとのこと良かったです。

>削除の方は行がなくなって値が減った結果を総計に反映する必要がある
あんまりいい方法ではないですが、簡単にやるとすればこんな感じでしょうか。
$(document).on(‘click’, ‘.remove-row-image-gaia’, function() {
var record = kintone.app.record.get();
myCalculate(record.record);
kintone.app.record.set(record);
});

やはり、テーブルの行追加・削除イベントをAPIで用意してほしいですね・・・

また何かありましたらお気軽にご質問ください。

落合様

削除時の処理はご提案頂いた方法の他、

$(document).on(‘DOMNodeRemoved’ , “table tbody”, function(e){

でも拾えるようで、動作を確認できました。
クラス名を使いたくない事もあり、こうしておこうと思います。

追加時のdisableの処理の方が難しいですね。

DOMNodeInserted でテーブル内を監視させると行の追加時、複数回のイベントが発生しますが、kintone側で行っている全ての処理が完了してからrecord値などを取らないとエラーになります(API内の処理上、NULLで引っかかるみたいです)。しかし、この完了を確認する方法が思いつかず…。
やはりAPIで追加・削除の完了イベントを取れるといいですねぇ…。

結局は処理の完了を待たず、複数回実行されますが、要素を直接disableにしたり、クラス名を入れてしまうことで逃げられなくもない、、、という結論になりました。

$(document).on(‘DOMNodeInserted’ , “table tbody tr”, function(e){
$(‘input[type=“text”]’, this).eq(8).attr(‘disabled’, ‘’).parent(‘div’).addClass(‘disabled-cybozu’);
});

eq(8)は開発中アプリの入力欄の位置関係で決まった値です(これも少し手抜きですが)。attr(‘disabled’)でフォームを変更不可に。さらに親要素のdivをグレー表示にしています。
前述の DOMNodeRemoved も同様ですが、クラス名を気にしなければ table.subtable-gaia としてあげるとテーブルフォームに絞れますが、現状のkintoneの要素上にtableの中のフォームが他にないことから、なくても問題ないみたいです。

これで大まかには完成でいいかな、、、ということでお客様に見せて反応をうかがってみたいと思います。お付き合いありがとうございました。

かなり強引にされたみたいですね。
$(document).on(‘DOMNodeInserted’ , “table tbody tr”, function(e){
$(‘input[type=“text”]’, this).eq(8).attr(‘disabled’, ‘’).parent(‘div’).addClass(‘disabled-cybozu’);
});
ここはDOM構造にかなり依存しているので、やはりバージョンアップ時に不安は残るかと・・・
しかし、他の方法もあまりいいもの思い浮かばないので致し方ないかと私も思います。

よい方法思い浮かびましたら、私からもこの質問を通してご連絡いたします。

落合様
度々御返事ありがとうございます。

そうなんですよね。結局、現状は生成されたHTML調べてDOMなりクラス名に頼るしかなさそうです。
CSSカスタマイズでも気になったのですが、将来、変更になり得る範囲とそうで無い部分がハッキリするか、フィールドコードなどからIDを取得できるようなAPIが用意されればいいのですが…。

少し方向性が違う方法ですが、プリントクリエイターの印刷ボタンを押した時にボタンのフォーム内の変数にrecord内容がjsonで渡されて、それがプリントクリエイター側に送られているようなので、この変数の内容を書換えてしまい、kintone側の0,N/A,自動計算の件は何もしない方向もあるかなぁ、とも考えているところです…。
上手く使えばkintone側のフォームで生成される値以外も渡して印刷できるような気もしています。

限定された環境中で回答見つけるために試行錯誤する状況は、パズルを解いているみたいで楽しいのですが、時間と工数が…w

Shobu Umemura様

>変更になり得る範囲とそうで無い部分がハッキリするか
これはハッキリしてもらえると嬉しいのですが、今後の開発を制限することになると思うので難しいかと思います。

>フィールドコードなどからIDを取得できるようなAPIが用意されればいいのですが…。
現在要素を取得できるAPIは、kintone.app.getFieldElementsとkintone.app.getFieldElementだけだったと認識しています。
しかし、それぞれ一覧と詳細画面のみでしか利用できないので、今回は利用できそうにないですね・・・

>上手く使えばkintone側のフォームで生成される値以外も渡して印刷できるような気もしています。
プリントクリエイターのJavaScriptを変更するのもありかと思います。
ただ、詳細画面からの個別出力と一覧画面の一括出力ではJavaScriptが異なっています。
個別出力ではrecord内容をそのまま渡しているのですが、一括出力では検索クエリーを渡しています。
そのため、一括出力の場合はrecordの内容を変更できない点に注意してください。
しかし、一括出力の方もrecord内容をjsonで渡すことができるAPIを用意してもいいかもしれません。

落合様

御返事ありがとうございます。
業務の性質的に一括印刷の場面がないので、その点は問題なさそうです。今から手もどし出来るか微妙ですが、プリントクリエイターのJS弄る方法も試してみようかと思います。

当初の投稿から内容がずれてしまいましたが、

★kintoneの追加API setFieldShown はテーブルの個別セルに対応していますか?
★APIによるテーブル行追加・削除の正式な方法

この2点も使い所がありそうなので気になっています。そのうちドキュメントに記載されるものでしょうか…。

Shobu Umemura様

★kintoneの追加API setFieldShown はテーブルの個別セルに対応していますか?
JavaScriptを見るとkintone.app.record.getFieldElementで呼び出しているfunctionで要素を取得しているっぽいので、kintone.app.record.getFieldElementの取得できないフィールドには対応していないのではないかと思います。
https://cybozudev.zendesk.com/hc/ja/articles/201942014#step3
ただ、サブテーブルは取得できないと記載されていますが、実際は取得できますね・・・
ここらへんのドキュメントの改善要望をサイボウズに言ってみます。

★APIによるテーブル行追加・削除の正式な方法
場所としては、kintone.event内で行うかkintone.app.record.setで行うかだと思います。
方法は特に正式な方法というのはないかと思います。

リリースされたばかりで私もまだドキュメント以上のことは把握できていないので、良いアドバイスができず申し訳ありません。

落合様

setFieldShown の件はなるほど、仕方がないですね。まぁ、ここまでの流れと同じく強引にやってしまえばいい訳ですが(ドンドン方向性が崩れて言っている気が…)。

テーブル行の削除なのですが、REST APIに倣ってrecord内のテーブル各行のvalueを""とすればよいと考えているのですが、どうも上手く行かないケースがあり、サンプルコードなどがドキュメントにあれば、という希望です。
このスレの頭で空セルを含む行を削除させていたときは問題なかったのですが、、、

Shobu Umemura様

getFieldElementの取得できないフィールドですが、ドキュメントの更新が遅れているようです。
7/13のアップデートで、サブテーブル/関連レコード一覧/グループに対応したようです。

テーブルの行削除ですが、追加・編集イベント内でしたら、
var table = event.record.Table.value;
table.splice(1, 1);
それ以外では、
var record = kintone.app.record.get();
var table = record.record.Table.value;
table.splice(0, 1);
kintone.app.record.set(record);

としてみました。一応動作確認もしたので動くかと思います。
参考になりますでしょうか?

落合様

お返事ありがとうございます。
行削除できない原因は私のミスでした。
次々に拡張しているせいでevent処理のコードが散らばる状況の中、ある .submit の中で return event; していないのが原因だったようです。
お騒がせしました。

ご回答のコードはとても参考になると思います。
引き続きよろしくお願いいたします。

Shobu Umemura様

とりあえず解決したようで良かったです。
return event;を忘れるの私もたまにしてしまいます(^^;

またなにかあればお気軽にご質問ください。

shobu Umemura様、落合様

途中から入ってすみません。
初心者です。

同じ課題があり、落合様が作られたサンプルプログラムを利用しようとしましたが、
うまく入力と計算までできたのですが、レコードを「保存」できなくなりました。

何か足りない気がしますが、どうすればいいのでしょうか?

お手数をおかけしますがよろしくお願いします。