Retoolでのスクリプト記述

JSコードの実行(JavaScriptを使用したカスタム動作の実行)

Retoolでは、JavaScriptのメソッドによって、コンポーネントおよびクエリーと相互作用することが可能です。これは、Inspecorタブに表示されるプロパティを介して、現在サポートされていないコンポーネント間の相互作用を作成する際に役立ちます。

この機能を使用するには、下部のパネルを開いて、クエリーを新規作成し、Select resource ドロップダウンでRun JS Codeを選択します。

1462

このようにRetoolではプログラムを使用してコンポーネントのプロパティを設定したり、クエリーをトリガーしたり、役に立つJavaScriptのライブラリーにアクセスしたりすることができます。以下に、Retoolアプリを次のレベルに進めるためのJavaScriptの使用方法の例をいくつか紹介します。

📘

安全第一

すべてのJavaScriptをコード・スニペットとして使用できるわけではありません。すべてのユーザーの安全と安心を確保するために、ブラウザーおよびRetoolアプリ外のコンテキストに対する特定の操作は実行されません。例えば、ブラウザー・イベントやjQueryなどのライブラリーにアクセスすることはできません。

例: CSVファイル内の各行にAPIリクエストを実行する

この例では、CSVファイルの各行にAPIリクエストを実行し、その過程でCSVファイルの各行において発生したエラーを示します。

1. CSVファイルをアップロードする

FilePickerコンポーネントとTableコンポーネントを作成します。RetoolにアップロードしたCSVファイルをプレビューするためにテーブルを使用します。そのために、TableのDataプロパティをfilepicker1.parsedValueに設定します。FilePickerコンポーネントがCSVファイルとJSONファイルを自動的に解析するので、parsedValueプロパティでそれらの値にアクセスすることができます。

1304

2. クエリーを作成する

CSVファイルを関連付けたので、テーブル内の各行に実行するクエリーを作成します。デフォルトでは、iプロパティは0になります。この例でのJavaScriptコードではiプロパティを置き換えることにより、クエリーの実行全体において、このクエリーが様々なデータに対して実行されるようにします。

1852

3. ボタンを追加して、CSVファイル内の各行にquery1を実行させる

2つのTextコンポーネントを作成します。1つはリクエストの現在のステータス(例: 処理数)を示すためのもので、1つはCSVファイルの処理中に発生したすべてのエラーを示すためのものです。また、このプロセスをトリガーするボタンを追加します。

778

次に、button1に以下のJavaScriptのクエリーをトリガーさせます。

var rows = filepicker1.parsedValue;
var errors = '';
var total = rows.length;

function runQuery (i) {
  // statusTextを現在の進捗状況で更新します
  statusText.setValue(i.toString() + '/' + total.toString())
  
  if (i >= rows.length) {
    console.log('Finished running all queries');
    return;
  }

  console.log('Running query for row', i);

  query1.trigger({
    additionalScope: { i: i }, // ここでステップ2の変数`i`を上書きします
    // onSuccess関数でデータを取得するために引数を使用することができます
    onSuccess: function(data) {
      runQuery(i + 1);
    },
    onFailure: function(error) {
      // errorsTextを発生したすべてのエラーで更新します
      errors += 'Found error at line ' + i.toString() + ':  ' + error +  '\n\n';
      errorText.setValue(errors);
      runQuery(i + 1);
    }
  });
}

runQuery(0);

4. 使用してみる

この例でのAPIのエンドポイントである https://approvals.tryretool.com/api/users/approve は実在しないため、すべてのリクエストが失敗しますが、各行においてエラーが発生していることが分かります。

816

一般的なユース・ケース

クエリーの実行後に状態をクリアする

クエリーを実行した後に状態をクリアするには、以下のコード・スニペットを使用することができます。

userInput.setValue('');
emailInput.setValue('');
pricingTierDropdown.setValue(null);

クエリーをトリガーする

プログラムを使用してクエリーをトリガーするには、以下のように入力します。

query1.trigger()

クエリーの動作をカスタマイズするために追加の引数を渡すこともできます。以下に、その例を示します。

query1.trigger({
  additionalScope: {
    name: 'hi',
  },
  // onSuccess関数でデータを取得するために引数を使用することができます
  onSuccess: function(data) {
    console.log('Successully ran!');
  }
})

additionalScopeオプションを選択することによって、グローバル・スコープで定義されていない追加の変数をクエリーに渡すことができます。query1では、{{name}}を使用して、追加したスコープによって定義された新しい変数を参照することができます。

関数が正常に終了すると、コールバック関数であるonSuccessがコールされます。

クエリーのトリガー元を取得する

変数triggeredByIdは、クエリーをトリガーしたコンポーネントの名前を返します。クエリーを実行するようトリガーしたコンポーネントの名前を返すために、どのような種類のクエリー内でも、{{ }}の内側でこの変数を参照することができます。クエリーが別のクエリーによってトリガーされた場合には、triggeredByIdundefinedを返します。

text1.setValue("I was triggered by component: " + triggeredById)

トリガー元のコンポーネントのインデックスを取得する

ListViewまたはテーブル内のコンポーネントによってクエリーがトリガーされた場合、そのクエリー内で変数iを定義すると、そのListViewまたはテーブル内のコンポーネントのインデックスが返されます。

text1.setValue("I was triggered by component at index: " + i)

配列の各項目にクエリーをトリガーする

以下に、その完全な例を示します。

var rows = [{ a: 1 }, { a: 2 }, { a: 3 }, { a: 4 }];

function runQuery (i) {
  if (i >= rows.length) {
    console.log('Finished running all queries');
    return;
  }
  var data = rows[i];
  console.log('Running query for row', data);

  query1.trigger({
    additionalScope: {
      data: data
    },
    // onSuccess関数でデータを取得するために引数を使用することができます
    onSuccess: function(data) {
      runQuery(i + 1);
    }
  });
}

runQuery(0);

データを返す

JavaScriptのクエリーは、コンポーネントとクエリーを操作するだけでなく、データを返すこともできます。例えば、JavaScriptのクエリー内で乱数を生成し、他の場所でそれを使用したいとします。そのためには、まず、クエリー内に単純なJavaScriptを記述します(この「クエリー」をgenerateRandomNumberとします)。

return Math.random()

このクエリーをトリガーすると、このクエリーの.dataプロパティを介して、生成された数字にアクセスすることができます(すなわち、{{ generateRandomNumber.data }}となります)。

Promiseと非同期クエリー

JavaScriptのクエリーは非同期にすることもできます。Promiseを返す場合、Retoolはクエリーが「完了」したとみなす前に、Promiseが解決されるまで待機します。

単純な非同期処理

トリガーするクエリーをPromise.resolve()の1番目の引数として渡すと、他のクエリーがトリガーされ、クエリーが終了するまで待機し、その後、トリガーされたクエリーの.dataの結果を返します。

return Promise.resolve(query1.trigger())

クエリーが返すデータの配列の非同期処理

クエリーのトリガーに依存している項目の配列を渡すこともできます。Promise.all()を使用して、同じ長さの配列ですべての結果を返します。この場合、table1の各行にquery1をトリガーし、各行のidの値を渡します。query1の中で{{id}}を使用すると、実行されたときに、渡された行のidとして評価されます。

const promises = table1.data.map(row => {
    return query1.trigger({
        additionalScope: {
            "id": row.id
        }
    });
});

return Promise.all(promises);

解決と拒否

この場合、クエリーから値を返したいときに、その値をパラメーターとしてPromiseのresolve関数に渡すことができます。また、Promiseのreject関数を使用して、クエリーを失敗させることもできます。

以下の例では、クエリーは実行されるまで2秒待機し、resolve関数により12345を値として返します。

return new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(12345)
  }, 2000)
})

リファレンス: コンポーネントとクエリーのメソッド

すべてのクエリー

query.trigger(options)

「options」は、以下のいずれかのプロパティを含むオブジェクトです。

{
  additionalScope: {},
  onSuccess: (data) => { },
  onFailure: (error) => { },
}
  • additionalScopeオプションを使用すると、トリガーされるクエリー内で使用される変数を定義するか、additionalScopeオブジェクト内に存在するキー/値で上書きすることができます。例えば、additionalScope: { test: "New Value" }とした場合、トリガーされたクエリー内の{{test}}が実行時に「New Value」を返します。

🚧

additionalScopeのキーは、実行されるまで未定義となります

トリガーされるクエリーにおいて、additionalScopeオブジェクトに渡されるキーは、JavaScriptのクエリーによって実際にクエリーがトリガーされたときにのみ使用することができます。そのときまで、キーの値はundefinedと評価されます。

  • onSuccessオプションは、クエリーの実行が正常に終了したときに、クエリーのデータ(data)を引数としてコールされるコールバックです。
  • onFailureオプションは、クエリーの実行中にエラーが発生した場合に、そのエラー(error)を引数としてコールされるコールバックです。

また、.trigger関数は、解決されたPromiseをクエリーの.dataプロパティに返します。

query.reset()

この関数は、クエリーの.dataプロパティと.errorプロパティをクリアします。

一時的な状態

state.setValue(value)

一時的な状態変数の値を、引数として渡された値に設定します。

state.setIn(path, value)

特定の場所においてstate.valueの値を設定します。「path」変数は、選択するキー/インデックスの配列とすることも可能です。値は、その状態の他の値を破棄して再生成することなく設定されます。
state.setIn( [ 0, "trout" ], {length_inches: 16 } )

コンポーネントにおけるJavaScriptのメソッド

Table(テーブル)

table.selectRow(index)

テーブル内で選択された行を、引数として渡されるインデックス(整数または配列)に変更します。「index」は、1つのインデックスまたは複数のインデックスの配列([0,4,8])とすることができます。「null」を渡すと、選択が解除されます。

table.selectPage(index)

テーブル内で選択されたページを、引数として渡されるインデックス(整数)に変更します。

table.setData(data)

引数として渡された値でTableのデータを上書きします。どのような入力タイプでも受け入れますが、複数のオブジェクトの配列または複数の配列で構成されるオブジェクトのみが正しく表示されます。
[ { key1: val, key2: val }, { key1: val, key2: val } ] or { key1: [val, val], key2: [val, val] }

table.setSort(columnName, descending)

「columnName」(文字列)をキーとして、指定された方向にテーブルをソートします。降順の場合は「true」、昇順の場合は「false」になります。
table.setSort("name", true)

「null」を渡すと、テーブルのソートがリセットされます。
table.setSort(null)

Text(テキスト)コンポーネント

text.setValue(string | number | null)

Textウィジェットのテキスト値を、引数として渡された値に設定します。

Text Input(テキスト入力)

textinput.setValue(string | number | null)

「textinput」の値を、引数として渡された文字列または数値に設定します。「null」を渡すと、コンポーネントがクリアされます。

textinput.focus()

テキスト入力にフォーカスを移動して、ユーザーのカーソルで入力項目内が選択されます。

Checkbox(チェックボックス)またはCheckbox Group(チェックボックス・グループ)

checkbox.setValue(bool)

Checkboxの値を、引数として渡されたブール値に設定します。ここで「null」を渡すとCheckboxの値がnullに変わりますが、画面上のチェックボックスのチェックは解除されません。

Rich Text Editor(リッチ・テキスト・エディター)

texteditor.setValue(string)

Rich Text Editorの値を、引数として渡された値に設定します。

JSON Editor(JSONエディター)

jsoneditor.setValue(value)

JSON Editorの値を、引数として渡された値に設定します。

JSON Schema Form(JSONスキーマ・フォーム)

jsonschemaform.clear()

JSON Schema Formの入力内容をすべてクリアします。

Date Time Picker(日時取得)とDate Range Picker(日付範囲取得)

datetimepicker.setValue(string | date)

Date Time Pickerの値を、引数として渡された値に設定します。また、文字列の値を日付として解析します。

daterangepicker.setStartValue(string | date)

daterangepicker.setEndValue(string | date)

Date Range Pickerの開始値または終了値を、引数として渡された値に設定します。また、文字列の値を日付として解析します。

daterangepicker.setRange( [ startValue, endvalue ] )

Date Range Pickerの開始値と終了値を設定します。2つの日付または文字列の配列を、開始値と終了値の引数として受け取ります。

Form(フォーム)

form.clear()

Formの入力内容をすべてクリアします。

Tabbed Container(タブ付きコンテナー)

tabbedcontainer.selectTab(index)

タブ付きコンテナー内で選択されたタブを、引数として渡されるインデックス(整数)に変更します。

Container(コンテナー)

container.scrollIntoView({behavior: string})

Containerコンポーネントまでページをスクロールします。スクロールの動作を変更するbehaviorオブジェクトを受け取ります。「behavior」の値には「smooth」または「auto」を設定します(例: {behavior:'smooth'})。

Modal(モーダル)

modal.open()

モーダルを開きます。

modal.close()

モーダルを閉じます。

Select(選択)とMultiSelect(複数選択)

select.setValue(string | number | null)

Selectコンポーネント(ドロップダウン)の値を、引数として渡された値に設定します。

multiselect.setValue(string[] | number[])

MultiSelectコンポーネントの値を、引数として渡された値に設定します。MultiSelectの.valueプロパティは配列であるため、引数は配列にする必要があります。

IFrame

iframe.reload()

引数は不要です。対象のiFrameコンポーネントの現在のURLを再度読み込みます。

Radio Group(ラジオ・グループ)

radiogroup.setValue(string | number | null)

Radio Groupの値を、引数として渡された値に設定します。

Button Group(ボタン・グループ)

buttongroup.setValue(string)

Button Groupの値を、引数として渡された値に設定します。

Rateing(評価)

rate.setValue(number)

Ratingコンポーネントの値を、引数として渡された値に設定します。

FilePicker(ファイル取得)

filepicker.reset()

「filepicker」をデフォルトの状態(ファイルが選択されていない状態)に戻します。

ユーティリティー

utils.openUrl(url, inNewPage)

デフォルトでは、URL(文字列)を新しいページで開きます。2番目の引数にfalseを渡すことで、URLを同じページで開くように設定することもできます。

utils.downloadFile(data, fileName, fileType)

可能であれば、「fileName」(文字列)と「fileType」(文字列)を使用して、「data」の値をダウンロードします。

👍

RESTQuery1http://somewebsite.com/metrics.pdf からデータをフェッチします。

「metrics.pdf」をダウンロードするにはutils.downloadFile(RESTQuery1.data)をコールします。
同じファイルを「custom_file.docx」としてダウンロードするにはutils.downloadFile(RESTQuery1.data, 'custom_file', 'docx')をコールします。

utils.showNotification({ title: string, description: string, notificationType: string })

画面の右上隅に通知メッセージを表示します。これを使用して、クエリーが失敗した後にエラー・メッセージなどのメッセージを表示します。TitleとDescriptionは文字列です。notificationTypeでは、'info' | 'success' | 'warning' | 'error'の文字列を受け取ります。

localStorage.setValue(key, value)

キー/値のペアをlocalStorageに保存します。キーは文字列でなければなりません。値は任意のタイプにすることができます。{{ localStorage.values.yourKey }}を使用して、localStorageのデータに他の場所からアクセスすることができます。また、JavaScriptのlocalStorage.clear()関数を使用して、localStorageをクリアすることができます。

ヒント: localStorageから1つのキー/値のペアを削除するには、値を「undefined」に設定して、localStorage.setValue("removeThisKey",undefined)のように記述します。

utils.downloadPage(fileName, { selectorsToExclude, componentsToExclude, scale, fullscreen })

現在表示しているRetoolページをPDF形式でダウンロードします。

プロパティ注意事項
fileNameString必須: エクスポートしたファイルに使用する名前です。
componentsToExcludeString[]オプション: スクリーンショットから除外するコンポーネントの配列を名前(例: ['select1', 'textinput1'])で指定することができます。
selectorsToExcludeString[]オプション: スクリーンショットから除外するコンポーネントの配列をCSSセレクター(例: ['._retool-text4'])で指定することができます。
scaleNumberオプション: 解像度を設定する「scale」パラメーターを数値で渡すことができます(デフォルトではwindow.devicePixelRatio)。
fullscreenBooleanオプションtrue: プレゼンテーション・モードでアプリ全体をエクスポートします。

🚧

既知の制限事項

iFrameに埋め込まれたカスタム・コンポーネントとその他の要素はエクスポートしたPDFには表示されません。

ライブラリー

{{ }}の内側に記述するものはJavaScriptです。Retoolでは、以下のユーティリティー・ライブラリーを用意しています。

名前ドキュメントバージョン
lodashhttps://lodash.com/docs/4.17.4
momenthttps://momentjs.com/docs/2.18.1
uuidhttps://github.com/kelektiv/node-uuidv1v4の両方。uuid.v1()またはuuid.v4()を使用します
numbrohttps://github.com/BenjaminVanRyseghem/numbro2.1.0