スポンサーリンク

【pleasanter】分類項目の複数選択の値の取得、設定

プリザンター
スポンサーリンク
※当サイトは広告を含みます

※おことわり
2025年12月時点の情報です。プリザンターのバージョンは 1.4.22.0 です。Google Chrome でやっています。
javascript,html,cssともに初心者です。調べながら、やってみながら、きっとこうすればいいんだ!という感じで書いていますので、間違っている、または効率的な書き方ではない可能性が大いにあります。間違ってるよ!とか、こうしたほうがいいよ!ということがありましたら、コメント等で教えていただけると大変ありがたいです。

1.はじめに

スクリプト、サーバースクリプトで複数選択の項目を操作しようとして「ぐぬぬ。今日はこの辺で勘弁してやろう。来週きっちり落とし前つけてやる。」と画面に向かってつぶやきつつ退散し、家に帰ってからこっそりやりかたを調べてみました。
ということで、ここにつらつら書いていきます。JSON文字列?ぬ?となってしまう感じの非エンジニア事務員が書く、初心者向けの内容です!

やってみてなんとなくわかったのは、複数選択項目は配列として扱う。値を設定する際は、値を配列としてまとめてからカンマ区切りの文字列(JSON文字列?)にしてから、突っ込むとよいらしい、ということでした。

2.分類項目を複数選択可とする

そもそも。分類項目で複数の値を選択できるようにするには、エディタで「複数選択」のチェックをオンにします。
複数選択可が設定できるのは分類項目だけで、「状況」「担当者」「管理者」では、設定できません。
なお、分類項目であってもコントロール種別を[ラジオボタン]にしている場合、複数選択可としていても有効になりません。

■ テーブルの設定>エディタ>分類項目の詳細設定
※スタイルは[ノーマル]でも問題ありませんが、複数選択して選択肢がはみ出そうな場合、スタイルを[ワイド]にするのがおすすめです。

■ 複数選択可としたときのイメージ

3.複数選択としている分類項目の規定値の設定

複数選択にしている場合の規定値の設定方法
こちらの記事を参考とさせていただきました。ありがとうございました。いやー。知らなかった!
https://devops-blog.virtualtech.jp/entry/20241018/1729234554

複数選択の場合、[“りんご”] のように、配列の書き方で設定すると規定値が設定できます。

4.スクリプトでの値の取得、設定

(1)値の取得

複数選択の分類項目から値を取得すしたいとき、スクリプトでは単一選択の時と同じ書き方で値の取得ができました。
ただし、複数選択の場合帰ってくる値が配列となります。

以下の例使用する分類A、分類Bは以下の設定としています。
分類A:複数選択、選択肢 りんご、ばなな、なし、キウイ
分類B:複数選択、選択肢 ユーザー

$p.events.on_editor_load = function () {
  const valuesA = $p.getValue('ClassA');
  console.log(valuesA);
  console.log(valuesA[0]);
  const valuesB = $p.getValue('ClassB');
  console.log(valuesB);
  console.log(valuesB[0]);
}
コンソール出力結果

(2)値が設定されていない場合の判定方法

値が選択されていない場合、空の配列が取得される値となります。

値が空白の場合のイメージ

選択された値があるかどうかを判定する場合、取得した配列に入っている値の個数で判定します。値の個数が0の場合、選択された値がない、ということになります。
配列.lengthで「配列に値が何個入っているか」を取得できます。配列の長さを取得する、とも言います。

以下コード例では、分類Aの選択肢に変化がある都度実行され、選択されていない場合「値が選択されていません」とコンソールに出力、選択されている場合は選択されている値の個数をコンソールに出力します。

$p.on('change','ClassA',function() {
  const count = $p.getValue('ClassA').length; 
  if(count === 0) {
    console.log('値が選択されていません');
  } else {
    console.log(`${count} 個の値が選択されました`);
  }
})

値を一つ一つ処理したい場合のコード例。
ちなみに以下の書き方では、何も選択されていない場合、エラーとはならず、なにも処理されずに終わります。

$p.events.before_validate = function() {
  const values = $p.getValue('ClassA');
  for ( let value of values) {
    console.log(value);
  }
}

(3)値の設定

スクリプトでの値の設定方法は、複数選択の場合、ちょっと違います。
配列を文字列にしてセットする、という方法になります。

以下のコードは、更新ボタンを押したら分類Aに りんご、なし を設定する、というコード例です。
配列を用意して(arr)、JSON.stringify でJSON文字列にしてセットしています。

$p.events.before_send_Update = function () {
  const arr = ["りんご","なし"];
  $p.set($p.getControl('ClassA'), JSON.stringify(arr));
}

ちなみに、複数選択の項目に一つだけ値をセットしたいときも同様に配列にして、文字列変換してセット、という流れを取ります。

  const arr = ["りんご"];
  $p.set($p.getControl('ClassA'), JSON.stringify(arr));

空欄にしたい場合は、以下のコードとしてみたらできました。

  const arr = [];
  $p.set($p.getControl('ClassA'), JSON.stringify(arr));

ですが、単一項目と同様に以下のコードでも大丈夫でした。

$p.set($p.getControl('ClassA'), ""));

4.サーバースクリプトでの値の取得、設定

(1)値の取得

サーバースクリプトでは model.ClassA 等とすると、項目の値を取得することができます。
複数選択の項目でも同様に値が取れます。
が、取得した値は一見配列のように見えて、文字列なんです!びっくり。
なので、取得した文字列を JSON.parse で配列に変換します。

const val1 = model.ClassA;
context.Log(`val1: ${val1}`);
context.Log(`val1が配列かどうか:${Array.isArray(val1)}`);

const val2 = JSON.parse(model.ClassA);
context.Log(`val2が配列かどうか:${Array.isArray(val2)}`);
context.Log(`val2の最初の値:${val2[0]}`);
値の取得 サーバースクリプト

model.ClassAとして取得した値の val1 は一見配列のように見えるのですが、文字列なんです!いやー、だまされた!
JSON.parse をかけることで、javaScript で扱うことのできる配列オブジェクトになります。

(2)値が設定されていない場合の判定方法

配列の長さで判定します。
ただし、作成前は undefined となるので、注意が必要です。undefinde の状態で JSON.parse としたら「なんもないのにできるかい!」とエラーになってしまいました。
以下の例は、複数選択の model.ClassA の値を取得し、空欄の場合は「値が選択されていません」とコンソールに出力、値が選択されている場合は選択された値の個数をコンソールに出力するコードです。
model.ClassA が undefined の場合は false となるので、||の後の”[]”がJSON.parseに渡されます。

// model.ClassA が undefined なら "[]" をパースする
const values = JSON.parse(model.ClassA || "[]");
if (values.length === 0) {
  context.Log("値が選択されていません。");
} else {
  context.Log(`${values.length} 個の値が選択されました。`);
}

(3)値の設定

サーバースクリプトで値を設定する場会、通常は model.ClassC = “りんご”; のように書きます。

複数選択の項目にサーバースクリプトで値を設定する場合は、配列を用意し、JSON.stringify でJSON文字列に値をセットします。

//複数選択ではない場合
model.ClassC = "りんご";     
                         
//複数選択の場合
model.ClassA = JSON.stringify(["りんご","ばなな"]);   
//または
const arr = ["りんご","ばなな"];
model.ClassA = JSON.stringify(arr);

空の値をセットする場合は、空の配列をいれます。

const arr = [];
model.ClassA = JSON.stringify(arr);

5.例をやってみる

いくつかの例をやってみます。

(1)選択値の中に目的の値があるかを判定したい場合のコード例。

はい。AI先生に教えてもらいました。includes は配列に特定の値が含まれているかを調べてくれるメソッドだそうです。
【JavaScript】配列の includes() の使い方と注意点

■ テーブルの設定

項目表示名設定備考
分類Aくだもの選択肢:キウイ,バナナ,りんご
複数選択:ON

■ スクリプトの例(出力先:新規、編集)

$p.events.before_validate = function() {
  const trgValue = "キウイ";
  const values = $p.getValue('ClassA');
  if (values.includes(trgValue)) {
    console.log('キウイが選択されています。');
  } else {
    console.log('キウイが選択されていません。');
  }
}

■ サーバースクリプトの例(条件:作成前、更新前)

const trgValue = "キウイ";
const arr = JSON.parse(model.ClassB || []);
if (arr.includes(trgValue)) {
  context.Log(`${trgValue}が選択されています`);
} else {
  context.Log(`${trgValue}が選択されていません`);
}

(2)グループを選択したら、ユーザーをセットする

分類Aでグループを選択したら、分類B(複数選択)に選択したグループに所属するユーザーをセットする。というのをやってみます。

■ テーブルの設定

項目表示名設定備考
分類Aグループ選択肢:[[Groups]]
自動ポストバック:ON
分類B所属ユーザー選択肢:[[Users]]
複数選択:ON
設定項目設定内容備考
サイトのアクセス制御管理者:山田太郎
書き込み:
「Aプロジェクト」グループ
「Bプロジェクト」グループ
グループ「Aプロジェクト」グループグループID:1
グループ「Bプロジェクト」グループグループID:4

■ サーバースクリプト
TryCatch にチェックを入れ、条件は「計算式の前」としています。

if (model.ClassA) {
  //分類AからグループIDを取得
  const groupId = model.ClassA;
  //グループIDからグループオブジェクトを取得し、groupにセット
  let group = groups.Get(groupId);
  //変数(配列)membersを用意
  let members = [];
  //groupからGetMembersで所属メンバーを取得。メンバーを1つずつ順次処理。メンバーのユーザーIDを配列memberに代入
  for (let member of group.GetMembers()) {
      members.push(member.UserId);
  }
  //分類Bに配列を設定(JSON.stringifyで文字列にしてからセットする)
  model.ClassB = JSON.stringify(members);
}

■ 動作イメージ

できたっちゃできたけど、「更新」ボタン押さないと反映しなかった。なんでかしら。

(3)キーとなる項目、出力される項目とも複数選択の例

分類A(複数選択)でメニューを選んだら、対応する材料を分類B(複数選択)に出力する。メニューは複数選択可。

■ テーブルの設定

項目表示名設定備考
分類Aメニュー選択肢:カレー,ハヤシ
複数選択:ON
自動ポストバック:ON
分類B材料選択肢:玉ねぎ,人参,じゃがいも,肉,カレールー,デミグラスソース
複数選択:ON

■ サーバースクリプト

条件は「計算式の前」としました。

// model.ClassA が未選択なら何もしない
if (model.ClassA) {
  // メニューごとの材料一覧
  const recipeMap = {
    "カレー": ['玉ねぎ','人参','じゃがいも','肉','カレールー'],
    "ハヤシ": ['玉ねぎ','肉','デミグラスソース']
  };
  // 選択されたメニューを配列で取得
  const selectedMenus = JSON.parse(model.ClassA);
  // 全材料をまとめる配列
  let allIngredients = [];

  for (let menu of selectedMenus) {
    const ingredients = recipeMap[menu];
    //メニューが未定義の場合、次のメニューへ
    if(!ingredients) continue;
   // 材料を配列へ代入  
    for (let ingredient of ingredients) {
      allIngredients.push(ingredient);
      context.Log(ingredient);
    }
  }
  // 結果を出力
  model.ClassB = JSON.stringify(allIngredients);
}

■ 動作イメージ

◆ キー値が単一選択の場合のコード例

ちなみに、キーとなる分類Aが単一選択の場合、すごく簡単に書けます。分類Bに入れようとする値がもともと配列のため、そのままJSON.stringifyに突っ込んじゃえばよいのですね。

let data = {
  "カレー":['玉ねぎ','人参','じゃがいも','肉','カレールー'],
  "ハヤシ":['玉ねぎ','肉','デミグラスソース'],
};

if (model.ClassA) {
  model.ClassB = JSON.stringify(data[model.ClassA]);
}

◆ スクリプトの場合のコード(出力先:新規、編集)

ちなみに、スクリプト用に書き換えると、以下のコードで同じ結果が得られました。(分類A,分類Bどちらも複数選択の場合のコード)

$p.on('change', 'ClassA', function () {
  const selectedMenus = $p.getValue('ClassA');
  if (selectedMenus.length > 0) {

    const recipeMap = {
      "カレー": ['玉ねぎ','人参','じゃがいも','肉','カレールー'],
      "ハヤシ": ['玉ねぎ','肉','デミグラスソース']
    };
    
    let allIngredients = [];
  
    for (let menu of selectedMenus) {
      const ingredients = recipeMap[menu];
      
      if(!ingredients) continue;
      
      for (let ingredient of ingredients) {
        allIngredients.push(ingredient);
        console.log(ingredient);
      }
    }
    $p.set($p.getControl('ClassB'),JSON.stringify(allIngredients));
  }
})

(4)複数選択のルックアップ

(3)の変型判。メニューを選ぶとほかの項目に材料が出力される、メニューと材料は別のマスタテーブルに持っていて、そのテーブルを参照する。というルックアップのような機能を複数選択でやってみます。

ルックアップは複数選択はできない、と書いてあったけど、やってみたらできた。。。?
けれどもここではあえて、サーバースクリプトでやってみます。

■ テーブルの設定

テーブルA

項目表示名設定備考
分類Aメニュー選択肢:[[9205]]
自動ポストバック:ON
①の例では複数選択OFF
②の例では複数選択ON
分類B材料選択肢:玉ねぎ,人参,じゃがいも,肉,カレールー,デミグラスソース,キャベツ,小麦粉
複数選択:ON

テーブルB(レシピマスタテーブル サイトID=9205)

項目表示名設定備考
タイトルメニュー
分類A材料選択肢:玉ねぎ,人参,じゃがいも,肉,カレールー,デミグラスソース,キャベツ,小麦粉
複数選択:ON

■ サーバースクリプト

① キー値が単一選択

const menuId = model.ClassA;
let results = items.Get(menuId);
let ingredients = [];
for (let result of results) {
  for (let value of JSON.parse(result.ClassA)) {
    ingredients.push(value);
  }
}
model.ClassB = JSON.stringify(ingredients);

② キー値が複数選択

キー値(分類A)が複数選択の場合、model.ClassAの戻り値は配列のため、JSON.parseする必要があります。
ループが多重となるため、AI先生からは forEach をお勧めされました。
また、Setだと、重複を自動では維持してくれるからいいよ、とおすすめされました。
ここではコードの解説は行いませんので、不明な場合はAI先生に聞いてみてください。

if (model.ClassA) {
  const menuIds = JSON.parse(model.ClassA); // 選択されたメニューID
  const ingredientSet = new Set();          // 重複を自動で排除する集合

  menuIds.forEach(menuId => {
    context.Log(menuId);
    const records = items.Get(menuId);
    for (let record of records){
      let values = JSON.parse(record.ClassA);
      for ( let value of values) {
        ingredientSet.add(value);
      }
    }
  })

  // Set → 配列に変換して保存
  model.ClassB = JSON.stringify([...ingredientSet]);
}

■ 動作イメージ

(5)ボタンを押したら複数選択の分類項目にユーザーを追加する

プロセスで「確認」ボタンを押したら、そのユーザーを分類項目(複数選択)に追加する、というのをやってみます。

■ テーブルの設定

項目表示名設定備考
分類A確認済ユーザー選択肢:[[Users]]
複数選択:ON

■ プロセスの設定

プロセスはボタンを表示し、内容を保存する、という機能を持たせたいだけなので、シンプルです。
データの変更や通知などは設定していません。

■ サーバースクリプト(出力:更新前)

//「確認」ボタン(プロセスIDが1)が押されたときに実行
if (context.ControlId === 'Process_1') {
  //ログインユーザーのIDをuserIdに代入
  const userId = context.UserId;
  //現在の分類Aの値をuserIdsに代入。値がない場合は空の配列を代入
  let userIds = JSON.parse(model.ClassA || "[]");
  //userIdsに現在のユーザーをプッシュ
  userIds.push(userId);
  //分類Aをいったん初期化
  model.ClassA = JSON.stringify([]);
  //分類Aに新たなuserIdをセット
  model.ClassA = JSON.stringify(userIds);
}

■ 動作イメージ

6.最後に

数、書いたら慣れた。
忘れないようにしよう!

7.参考文献、記事

公式マニュアル
テーブルの管理:エディタ:項目の詳細設定:複数選択

参考とさせていただいた記事

【JavaScript】配列の includes() の使い方と注意点

Pleasanterの分類項目で複数選択ONの時の既定値の設定方法

プリザンター入門が装いを新たに!

コメント

タイトルとURLをコピーしました