【UiPath】【Apps】デモアプリの実装に学ぶ👓

# はじめに

- 本記事は、公式ガイドのAppsのサンプルソースをみて気になった実装をメモしたものです。
- 記事の内容は、個人の見解または確認結果であり、UiPath の公式見解ではありません。
- 製品仕様や参考画像は2025年6月15日時点のもので構成しています。

# デモアプリの参考ページ

https://docs.uipath.com/ja/apps/automation-cloud/latest/user-guide/demos-summary

|アプリのトピック|アプリの概要|
|:---:|:---:|
|外部コンテキストを設定する|アプリケーションの起動時に外部コンテキストを設定できます。これは、ロボティック プロセス オートメーション (RPA) プロセスなど、他の場所からアプリを起動するときに特に役立ちます。|
|カスタム HTML: グラフを作成する|このアプリは、d3.js や chart.js などの JavaScript ライブラリを使用して、さまざまな種類のグラフを作成する方法を示しています。|
|カスタム HTML: 変数の関数を使用して対話型の円グラフを作成する|このアプリでは、エンティティ、[カスタム HTML]、および [編集グリッド] コントロールを組み合わせて、対話型の円グラフを表示します。|
|カスタム HTML: 日付/時刻選択を作成する|このアプリは、カスタムの日付時刻ピッカーを作成する方法を示しています。|
|カスタム HTML: パスワード フィールドを作成する|このアプリは、パスワード フィールドを作成する方法を示しています。|
|カスタム HTML: 署名入力フィールドを作成する|このアプリは、署名の入力フィールドを作成する方法を示しています。|
|アクション アプリを使用する|このアプリは、従業員のオンボーディング用の Action Center のフォームを作成する方法を示しています。|
|メディア: 画像をバインドする|このアプリは、メディア ファイルを [画像] コントロールにバインドする方法を示しています。|
|編集グリッド: エンティティを操作する|このアプリでは、[編集グリッド] コントロールを使用してエンティティを操作する方法を示します。|
|表: エンティティを操作する|このアプリでは、[表] コントロールを使用してエンティティを操作する方法を示します。|
|テキストボックス: 特定のプロパティを検出する|このアプリでは、[テキストボックス] コントロールのプロパティを活用する方法を示します。|
|日付の選択: 日付の検証|このアプリは、複数の日付検証フィールドを作成する方法を示しています。|
|カスタム リストを使用する|このアプリは、カスタム リストを作成する方法を示します。|
|Web アプリ: ブース アプリ|このテンプレートは、Studio Web のワークフローを利用して、エンド ユーザーからデータを収集する Web アプリを示します。|
|Web アプリ: メール生成アプリ|このテンプレートは、Studio Web のワークフローを利用してメールを生成する Web アプリを示します。|
|レスポンシブでモバイルフレンドリーな埋め込みアプリ|この Web ページは、画面サイズの変更に反応する埋め込みアプリを示します。|

# 実装メモ
## 外部コンテキストを設定する

![外部コンテキストの設定.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/27397a3c-112c-4cf9-8634-633c2eb05903.jpeg)

App.QueryParam() 関数をテキストのプロパティにバインドしておくことで外部引数を渡せるようになります。
（設定例）
App.QueryParam(Of Integer)("intv", 100).ToString

![外部コンテキストの設定2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/e80182fa-eef6-4002-9262-524b297ad465.jpeg)

アプリのURLの末尾（el=vb）の後ろに引数の情報を渡してみます。
「&{引数名}={値}」の形式で指定します。

```
https://cloud.uipath.com/{組織ID}/apps_/default/run/{省略}?el=vb&intv=250
```

![外部コンテキストの設定3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/cfeb2472-55ea-4efc-9e1f-c20478bd3784.jpeg)

## カスタム HTML

![カスタムHTMLグラフ作成.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/fd304e67-9ea4-48d9-838d-467edb926db0.jpeg)

チャートのプロパティから「HTML」「CSS」「JAVASCRIPT」の編集が可能です。

![カスタムHTMLグラフ作成2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/a80600cb-553f-4488-898a-fb2380811127.jpeg)

![カスタムHTMLグラフ作成3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/9c9d8488-fd1b-4142-8c41-48dcf0ab32a5.jpeg)

### 変数の値の操作方法例

- ***変数の値を取得***　→　App.getVariable('sampleValue');
- ***変数に値を戻す***　→　App.setVariable('sampleValue', ★値);
- ***変数の値が変わったら同期する***　→　App.onVariableChange('sampleValue', value => { document.getElementById('asyncnum').value = value; });


具体的に説明するため、入力値を反映させるための入力欄を1つだけ持つカスタムHTMLを配置します。
あとは通常のテキストボックスを2つとボタンを1つ配置します。（下図）

![カスタムHTMLグラフ作成7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/37ac0ad1-b65d-4e3e-91cb-f11a3e8f2495.jpeg)

コードエディターを開き、次の内容を設定します。

```html: HTML
<div class="textContainer">
  値が変更されたら同期：
  <input type="text" name="asyncnum" id="asyncnum"  value="" style="width:22em" />
</div>
```

```javascript: JAVASCRIPT
// 初期値を非同期で取得して input にセット
(async () => {
  const internalValue = await App.getVariable('sampleValue') || "";
  document.getElementById('asyncnum').value = internalValue;
})();

// sampleValue が変更されたら input の値を更新
App.onVariableChange('sampleValue', value => {
  document.getElementById('asyncnum').value = value;
});
```
ページにアクセスすると、初期値を非同期取得しているため、上段と中段に値が入ります。

![カスタムHTMLグラフ作成4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/20342580-d3b7-4287-bf6d-4995c92f37f2.jpeg)

次に、下段の入力欄（「変更する値」）に値を入れてクリックします。

![カスタムHTMLグラフ作成5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/c64edad8-baa2-489b-a065-79fc15d82316.jpeg)

最後に中段の入力欄（「サンプル値1」）の値を変更し、上段と中段のみ変わることを確認します。

![カスタムHTMLグラフ作成6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/69d46fc3-8156-4626-98b2-ccb1fbbb03fe.jpeg)

デモアプリのグラフの値であれば、次の様にして変更できます。

```javascript:JAVASCRIPT
(async () => {
  // App 変数 'sampleValue' の値を取得
  const internalValue = await App.getVariable('sampleValue') || 0;

  const svg = d3.select('#bar-graph')
    .append('svg')
    .attr('width', 800)
    .attr('height', 400);

  const margin = { top: 20, right: 20, bottom: 30, left: 40 };

  const width = svg.attr('width') - margin.left - margin.right;
  const height = svg.attr('height') - margin.top - margin.bottom;

  const x = d3.scaleBand().range([0, width]).padding(0.1);
  const y = d3.scaleLinear().range([height, 0]);

  const data = [
    { date: '1 Jan 2023', value: internalValue },
    { date: '2 Jan 2023', value: 450 },
    { date: '3 Jan 2023', value: 400 },
    { date: '4 Jan 2023', value: 350 },
    { date: '5 Jan 2023', value: 300 },
    { date: '6 Jan 2023', value: 250 },
    { date: '7 Jan 2023', value: 200 },
    { date: '8 Jan 2023', value: 150 },
    { date: '9 Jan 2023', value: 100 },
    { date: '10 Jan 2023', value: 50 }
  ];

  x.domain(data.map(d => d.date));
  y.domain([0, 500]); // Set y-axis domain to match the data values

  const g = svg.append('g')
    .attr('transform', `translate(${margin.left}, ${margin.top})`);

  g.append('g')
    .attr('class', 'axis axis-y')
    .call(d3.axisLeft(y));

  g.append('g')
    .attr('class', 'axis axis-x')
    .attr('transform', `translate(0, ${height})`)
    .call(d3.axisBottom(x));

  g.selectAll('.bar')
    .data(data)
    .enter().append('rect')
    .attr('class', 'bar')
    .attr('x', d => x(d.date))
    .attr('y', d => y(d.value))
    .attr('width', x.bandwidth())
    .attr('height', d => height - y(d.value));
})();
```
（sampleValueの値を200とした例）
![カスタムHTMLグラフ作成8.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/46ad81dd-a1ce-45ce-b46f-48b617cc4556.jpeg)

## 画像のバインド
### メディアに登録した画像の表示

![画像のバインド.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/be62aa2a-8663-4b57-b3e3-250d4d9dd0d6.jpeg)

メディアにサンプル画像（face.jpg）を1つ追加します。
画像コンポーネントのソースに「Media.face_jpg」を指定します。

![画像のバインド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/01d40eb7-b868-43dd-aee7-2cb80c694374.jpeg)

### WEB上の画像の表示

プロパティのソースの詳細エディターにて、次の様に記述することでWEB上にアップロードされた画像も簡単に表示できます。（フリーアイコンズさんの画像を拝借）

***new AppsFile("https://free-icons.net/wp-content/uploads/2020/09/symbol011.png")***

![画像のバインド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/c932871d-655a-45d6-8e0c-a17c56498b1d.jpeg)

### ストレージバケットに登録した画像の表示

ストレージバケットをプロジェクトに追加します。

![画像のバインド5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/b49b5658-992c-4129-9ffb-e5951f2869fc.jpeg)

データ型：AppsFile の変数（sampleImage）を作成した後、
Mainページの読み込みイベントに「ストレージ バケットからファイルを取得]」のルールを設定します。

![画像のバインド6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/12279df9-c3aa-4bcf-a1fa-8eb26cee8e82.jpeg)

最後に画像コンポーネントのプロパティに変数（sampleImage）を設定したら完了です。

![画像のバインド7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/4fed67eb-aa7f-4cfb-91b1-4d90a14ce5b0.jpeg)

（読み込み例）
![画像のバインド4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/5b7ca6a0-e53b-4f04-8dc8-942e0c88e7fe.jpeg)

## 編集グリッドの操作

::: note warn
✔ こちらは Studio Web でアプリ作成した際の手順です。
次のAppsのガイドを参考にしていますが、若干イベントまわりの設定・記述は異なります。
https://docs.uipath.com/ja/apps/automation-cloud/latest/user-guide/use-datatable-with-table-and-edit-grid-controls
:::

説明用に「編集グリッド」「ボタン」「テキスト領域」を配置します。

![編集グリッド.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/b51bb0a2-b67e-480c-ac56-371053a6068b.jpeg)

画面左の***エクスプローラー ＞ App ＞ 右クリック ＞ アプリの変数***より、String と DataTable 型の変数を用意します。

![編集グリッド2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/75d022d1-dd19-4957-b186-2cafc024f0a5.jpeg)

![編集グリッド3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/6fe240de-799b-4ad0-b448-a90b9438f5c3.jpeg)

次に、MainPage の読み込みイベント（ワークフロー）を作成します。
「テキストからデータテーブルを生成」アクティビティをもちいて編集グリッドに表示するテーブルデータを用意します。
※出力先に先ほど作成したテーブル変数（tempTable）を設定します。

![編集グリッド4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/f3de1a6d-4931-4995-9790-d50f46bd300f.jpeg)

編集グリッドの全般タブに移り、データソースを設定します。
（例）***tempTable.ToListSource***

![編集グリッド5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/cd99116b-05c0-4709-8347-29ea35f756cb.jpeg)

***表示したい列はカラム名をソース欄に指定するだけです！***

![編集グリッド6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/9244ec3b-4298-4273-9169-dfb1dfc1ed0b.jpeg)

今度は編集グリッドを出力するためのイベント（ワークフロー）を設定します。
「データテーブルをテキストとして出力」を配置し、出力元のテーブルと出力先のテキストを次の様に設定します。
出力元テーブル：***Controls.MainPage.EditGrid.DataSource.data.CopyToDataTable***
出力先テキスト：tempArg

![編集グリッド7.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/c2ea73de-1a55-43fb-970b-3b44cbc5d251.jpeg)

最後に、編集内容を反映させるためのイベント（ワークフロー）を設定します。

::: note warn
イベントを設定しない限り、編集グリッドで作業後に「✔（更新）」ボタンを押下しても初期値に戻ってしまいます。
:::

![編集グリッド8.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/117223e5-21a1-4546-8564-e3b9341db04c.jpeg)

（行の変更時の例）
![編集グリッド9.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/d941b47e-a146-4d23-9a7b-2de9454a6012.jpeg)

更新対象の変数：***AppVariable.tempTable***
設定する値：***AppVariable.tempTable.UpdateRowAt(MainPage.EditGrid.RowIndex, MainPage.EditGrid.SelectedItem)***

（完成動作 - 起動後）
![編集グリッド10.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/6a08bede-6f69-45a3-bb4c-f60a5781fc48.jpeg)

（完成動作 - 編集後）
![編集グリッド11.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3301444/e769522a-6c1e-4619-b8ce-37797c9148e6.jpeg)

# さいごに
いかがでしたでしょうか。
カスタムHTMLやStudio Webのアプリ開発では、アプリ変数の扱いで結構沼にはまったので、これからAppsに取り組む方の役に立てばと書きました。
読んで助かった方がいたら(・∀・)ｲｲﾈ!!をポチっとお願いします！
最後までお読みいただきありがとうございました(・ω・)ノ