【Power Apps】初心者でもできる!Power Appsを活用した社内掲示板の実装 – 社内掲示板アプリ実装編①

前編の記事では、社内掲示板アプリのテーブル設計を紹介しました。

本記事では、社内掲示板アプリの実装を詳しく解説します。

初心者でも理解できるよう、関数、変数、実装のポイントについて細かく解説します。

すべての実装を一つの記事にまとめると長すぎると感じますので、
複数の記事に分けてアプリの実装を解説します。

今回は、社内掲示板アプリのヘッダー設計、Appコントロールの実装、投稿一覧画面の実装を中心に解説します。

社内掲示板アプリのデータベース

前編の記事では、以下のテーブルを設計しました。

BulletinBoard

列名データの種類
post_id (PK)オートナンバー
author (FK)一行テキスト
title一行テキスト
content複数行テキスト
type一行テキスト
created_by一行テキスト
created_on日付と時刻
modified_by一行テキスト
modified_on日付と時刻
delete_flagはい/いいえ選択肢

EmployeeMaster

列名データの種類
employee_id (PK)一行テキスト
employee_name一行テキスト
employee_email一行テキスト
created_by一行テキスト
created_on日付と時刻
modified_by一行テキスト
modified_on日付と時刻
delete_flagはい/いいえ選択肢

Read

列名データの種類
read_id (PK)オートナンバー
post_id (FK)一行テキスト
reader (FK)一行テキスト
created_by一行テキスト
created_on日付と時刻
modified_by一行テキスト
modified_on日付と時刻
delete_flagはい/いいえ選択肢

BoardComment

列名データの種類
comment_id (PK)オートナンバー
comment_author (FK)一行テキスト
post_id (FK)一行テキスト
comment_content複数行テキスト
created_by一行テキスト
created_on日付と時刻
modified_by一行テキスト
modified_on日付と時刻
delete_flagはい/いいえ選択肢

Power Apps開発の基本知識

Power Appsでは、テキストボックス、ドロップダウン、画面などのオブジェクトを「コントロール」と呼びます。

↓これらは「コントロール」です


各コントロールのコードを記述する部分や、コントロールの性質をカスタマイズできる部分は「プロパティ」と呼ばれます。

↓これらは「プロパティ」です

ヘッダーを作成

以下のオブジェクトを作成してヘッダーにしたいです。

左上のホームアイコンをクリックすると、投稿一覧画面に遷移します。これは、各画面に必要なホームページに遷移するボタンです。

各画面にこのオブジェクトを作成するには、テキストボックス、「ホーム」アイコン、四角形のコントロールを作成し、

  1. 3つのコントロールCtrl+Gでグループ化して、各画面にコピペします。
  2. コンポーネントを先に作成しておき、各画面にコンポーネントを設置します。(コンポーネントの作成方法は本記事で割愛します)

という2つの方法で、各画面に同じオブジェクトを配置することができます。

さらに、「ホーム」アイコンにOnSelectプロパティNavigate関数を記述すれば、画面遷移機能を作成できます。

Appコントロールを実装

アプリの全画面に適用したいグローバル関数やコレクションが存在する場合、AppコントロールのOnStartプロパティにコードを記述することをおすすめします。

Appコントロールはこちらです↓

AppのOnStartプロパティにコードを記述すると、アプリを起動する際に最初に実行されます。そのため、Power Appsの実装では基本的にログインユーザーなどの情報をOnStartプロパティに記述します。

今回の社内掲示板アプリのOnStartプロパティには、以下のコードを記述します:

Set(//ログインユーザー情報
LoginUser,
LookUp(
EmployeeMaster,
employee_email = User().Email
)
);
ClearCollect(//社員テーブルをコレクションに格納
colEmployee,
ShowColumns(
Filter(
EmployeeMaster,
delete_flag = false
),
delete_flag,
employee_id,
employee_email,
employee_name
)
)

以上のコードの説明は以下の通りです。

  • Set関数を使って、LoginUserというグローバル変数を作成し、社員テーブルのEmployeeMasterから、ログインユーザーのemailアドレスと一致する最初のデータを検索し、LoginUserに格納します。
  • ClearCollect関数を使って、colEmployeeというコレクションを作成し、社員テーブルのEmployeeMasterに対してFilter関数を使って条件と一致するレコードを抽出します。抽出されたEmployeeMasterのデータがcolEmployeeコレクションに格納されます。

LookUp関数を使えば、データソースから検索条件と一致する最初のレコードを検索できます。

構文は以下の通りです:

LookUp(データソース, 条件式)

Power AppsのSet関数は、グローバル変数を作成する際に使用される関数です。グローバル変数はすべての画面に適用されますが、ローカル変数は画面遷移時に別の画面では適用されません。そのため、ログインユーザー情報を格納するには、グローバル変数が最適です。

Set関数の構文は以下の通りです:

Set(変数, 値)

ClearCollect関数は、コレクションを作る関数です。

構文は以下の通りです:

ClearCollect(コレクション, アイテム)

ClearCollect関数の詳細はこの記事で紹介されていますので、ご参考いただければと思います。

投稿一覧画面を実装

前編の記事では、投稿一覧画面のイメージを以下に示します。

この画面イメージに基づいて、投稿一覧画面を実装します。

まず、「投稿一覧画面」、「新規投稿画面」、「投稿詳細画面」のページを作成します。
(この記事ではHome、New_Post、Post_Commentと命名しましたが、名前は任意で構いません)

投稿一覧画面のOnVisibleプロパティ

新しい画面の作成が終わったら、投稿一覧画面のOnVisibleプロパティに次のコードを記述します:

Clear(colBulletinBoardWithRead);
Concurrent(
ClearCollect(
colBulletinBoard,
ShowColumns(
Filter(
BulletinBoard,
delete_flag = false
),
post_id,
author,
content,
created_by,
created_on,
delete_flag,
modified_on,
modified_by,
title,
type
)
),
ClearCollect(
colRead,
ShowColumns(
Filter(
Read,
delete_flag = false And reader = LoginUser.employee_id
),
reader,
post_id,
delete_flag,
modified_by,
modified_on,
created_by,
created_on
)
)
);
ForAll(
colBulletinBoard As _rec,
Collect(
colBulletinBoardWithRead,
{
post_id: _rec.crcad_postid,
author: _rec.crcad_author,
content: _rec.crcad_content,
created_by: _rec.crcad_created_by,
created_on: _rec.crcad_created_on,
modified_on: _rec.crcad_modified_on,
modified_by: _rec.crcad_created_on,
title: _rec.crcad_title,
type: _rec.crcad_type,
read: If(
_rec.crcad_author = LoginUser.employee_id,
"自分の投稿",
If(
!IsBlank(
(LookUp(
colRead,
_rec.crcad_postid = crcad_post_id
))
),
"既読",
"未読"
)
)
}
)
);

上記のコードについて解説します:

  • ClearCollect関数を使ってcolBulletinBoardコレクションを作成し、BulletinBoardテーブルをFilter関数で検索条件と一致するレコードを絞り込んで、colBulletinBoardコレクションに格納します。
  • ClearCollect関数を使ってcolReadコレクションを作成し、ReadテーブルFilter関数で自分が既読者のレコードを絞り込んで、colReadコレクションに格納します。
  • Concurrent関数を使って、上記の二つのClearCollect関数の実行を並列処理します。
  • ForAll関数を使用して、colBulletinBoardコレクションのレコードを一行ずつ取得し、Collect関数で作成したcolBulletinBoardWithReadコレクションに挿入します。その際、read列If関数colReadのデータを判断し、データを「自分の投稿」、「既読」、「未読」のいずれかに決定します。

Concurrent関数は、「コードの実行を並列処理する」関数であり、一般的にパフォーマンス改善のために使用されます。

例えば、Concurrent関数を使わずに以下のようにコードを記述すると、

    ClearCollect(
colBulletinBoard,
ShowColumns(
Filter(
BulletinBoard,
delete_flag = false
),
post_id,
author,
content,
created_by,
created_on,
delete_flag,
modified_on,
modified_by,
title,
type
)
),
ClearCollect(
colRead,
ShowColumns(
Filter(
Read,
delete_flag = false And reader = LoginUser.employee_id
),
reader,
post_id,
delete_flag,
modified_by,
modified_on,
created_by,
created_on
)
)

この場合、二つのコレクションが同時に作成されるのではなく、まずcolBulletinBoardが作成され、その後にcolReadが作成されるという直列処理となります。そのため、結果的に処理時間がより長くなります。

ForAll関数の構文は以下の通りです:

ForAll(データソース, 式)

ForAll関数は、データソースに対して式を評価します。上記の例で説明すると、次のようになります↓

新しく追加されたread列も、colBulletinBoardから一行ずつ評価される際に、colReadコレクションを参照しながらデータが追加されます。

投稿一覧画面にドロップダウンコントロールとボタンコントロールを実装

投稿一覧のデータをステータスと分類で絞り込むためにステータスと分類のドロップダウン、および新規投稿ボタンを実装します。

テキストボックス、ドロップダウン、ボタンを追加し、ステータスドロップダウンの名前をStatusDropdownに変、分類ドロップダウンの名前をTypeDropdownに変更します。

ステータスのドロップダウンのItemsプロパティに以下のコードを記述します:

["すべて","既読","未読","自分の投稿"]

分類のドロップダウンのItemsプロパティに以下のコードを記述します:

["すべて","告知","雑談"]

新規投稿ボタンをクリックすると、新規投稿画面に遷移するように実装します。OnSelectプロパティに以下のコードを記述します:

Navigate(New_Post,ScreenTransition.Fade)

Navigate関数を使えば、指定の画面に遷移できます。

投稿一覧画面にギャラリーを実装

ギャラリーの実装は、投稿一覧画面で最も重要な部分です。

ギャラリーコントロールには様々な種類がありますが、今回は「高さが伸縮可能な空のギャラリー」を選びます。

「投稿一覧画面」に「高さが伸縮可能な空のギャラリー」を設置したあと、ギャラリーのItemsに以下のコードを記述します:

If(
StatusDropdown.Selected.Value = "すべて",
If(
TypeDropdown.Selected.Value = "すべて",
colBulletinBoardWithRead,
Filter(
colBulletinBoardWithRead,
type = TypeDropdown.Selected.Value
)
),
If(
TypeDropdown.Selected.Value = "すべて",
Filter(
colBulletinBoardWithRead,
read = StatusDropdown.Selected.Value
),
Filter(
colBulletinBoardWithRead,
type = TypeDropdown.Selected.Value And read = StatusDropdown.Selected.Value
)
)
)

上記のコードは、If関数を使って条件分岐処理を行います。

If関数の構文は以下の通りです:

If(条件, 条件を満たす場合の結果, 条件を満たさない場合の結果)

または、

If(条件1, 条件1を満たす場合の結果, 条件1を満たさない場合の結果, 条件2, 条件2を満たす場合の結果, 条件2を満たさない場合の結果・・・)

文章で解説するとややこしくなりますので、図で上記コードの分岐条件を説明すると、こんな感じになります↓

ギャラリーのItemsプロパティの実装が完了したら、次はギャラリーにテキストラベル、ボタンを配置して実装します。

以下のテキストラベル、ボタンを用意します:

  • ステータステキストラベル
  • 分類テキストラベル
  • タイトルボタン
  • コメント数テキストラベル
  • 投稿者テキストラベル
  • 更新日時テキストラベル

ステータステキストラベルTextプロパティColorプロパティをそれぞれ記述します:

ステータステキストラベルのTextプロパティ

ThisItem.read

ステータステキストラベルのColorプロパティ

If(
Self.Text = "未読",
RGBA( //赤色
255,
0,
0,
1
),
Self.Text = "既読",
RGBA( //緑色
0,
200,
0,
1
),
Self.Text = "自分の投稿",
RGBA( //ブラック
0,
0,
0,
1
)
)

分類テキストラベルのTextプロパティ

ThisItem.type

投稿者テキストラベルのTextプロパティ

LookUp(
colEmployee,
crcad_employee_id = ThisItem.author
).crcad_employee_name

更新日時ステキストラベルのTextプロパティ

ThisItem.modified_on

コメント数テキストラベルのTextプロパティ

CountRows(
Filter(
BoardComment,
delete_flag = false And post_id = ThisItem.post_id
)
)

コメントテーブルのBoardCommentをコレクションに格納すると、運用する際にPower Appsの2000件問題に引っかかってしまうので、敢えてコレクションを作成せずに直接にデータソースに接続します。

次は、タイトルボタンの設計を解説します。

まず、Textプロパティに以下のコードを記述します:

Left(
ThisItem.title,
25
) & Char(10) & Last(
Split(
ThisItem.title,
Left(
ThisItem.title,
25
)
)
).Value

次にタイトルボタンの塗りつぶし(押された状態の塗りつぶし、ポイント時の塗りつぶしも含めます)を透明にし、罫線の値を0にします。

HoverColorプロパティ

RGBA(175, 191, 224, 1)

OnSelectプロパティに以下のコードを記述します:

Set(glbPost,ThisItem);
Navigate(Post_Comment,ScreenTransition.Fade)

タイトルボタンをクリックすると、グローバル変数にギャラリーの該当レコードのデータを格納し、投稿詳細画面に遷移します。

次に幅を420にし、Heightプロパティに以下のコードを記述します:

If(
Len(ThisItem.title) > 25,
33 * CountRows(
Split(
TitleButton.Text,
Char(10) //改行を意味する
)
),
33
)

上記のコードは「タイトルテキストの文字数が25文字を超えた場合、高さが33*タイトルの行数になる。25文字以下の場合は高さが33」を意味します。

Left関数は文字列の先頭の文字を返します。構文は以下の通りです:

Left(文字列, 返す文字の数)

Len関数単一の文字列の長さを数えて数値として返します。

CountRows関数はテーブルの行を数えて数値として返します。

Split関数は、テキストを分割してテーブルにします。例えば、「たまわのジャーナル」をSplit関数で「の」を区切り文字として分割する場合、以下のテーブルが作成されます:

Value
たまわ
ジャーナル

Split関数の構文は以下です

Split(テキスト, 区切り文字)

さらに、ギャラリーのTemplateSizeプロパティを215に設定し、TemplatePaddingプロパティを5に設定すると、例えば、タイトルテキストの文字数が25文字を超えて高さが66になった場合、該当の行が他の高さが33の行と比べて高くなります。

こんな感じです↓

 

以上で、投稿一覧画面のメイン機能の実装が完了しました。

ギャラリーのヘッダーの部分はUIだけの実装なので、特に注意事項がないので割愛します。
(ここの部分です↓)


次の記事では、投稿詳細画面と新規投稿画面の実装を紹介します。

まとめ

本記事では、

  • Power Appsのコントロールとプロパティの概念について解説しました。
  • 社内掲示板アプリの投稿一覧画面の実装ポイントについても説明しました。
タイトルとURLをコピーしました