Closed64

Power Apps 格闘戦

ARGIAARGIA

Microsoft Power Platform で頑張る。
環境は次の通り。

(Power)

  • Power Automate
  • Power Apps

(永続化)

  • SharePoint Online
  • Dataverse
ARGIAARGIA

20230710

#SharePoint

  • サイト作る
  • リスト作る
  • 適当にスキーマを組む
  • 頑張る
ARGIAARGIA

#SharePoint
「タイトル」列は消せない。非表示にはできる。

ARGIAARGIA

#Dataverse
データの要件的にドキュメント志向なデータベースだとすっごい話が早い。
でも Dataverse で NoSQL 的操作ができるような情報が見えてこない。Azure Cosmos DB とコネクタでつながらないとだめですか?

ARGIAARGIA

#PowerApps
わからないことは次の通り。

  • グローバルGUIの最善慣行が見えてこない。コンポーネントでやればいいと思ったが、画面からコンポーネントを参照すると内部のコンテナ等にアクセスできないため意味がない。
  • Automate とコンポーネントを束縛させる方法もよくわからない。Automateの関数名.Run()でいいならそれでいいんだけど。
  • カスタムコンポーネントを作るとき、カスタムプロパティの関数だかイベントだかアクションだかの違いがわからない。なんだこれ?
ARGIAARGIA

#PowerApps
フォームでやるとどうしてもスマホ特化の見た目になるせいでレスポンシブ[1]ではない。

脚注
  1. レスポンシブとは「パソコン」と「スマホ」両方にスクリーンの見た目を合わせることをいう。スマホ特化はどちらかっていうとモバイルファースト。 ↩︎

ARGIAARGIA

#PowerApps
Patch関数を用いることで、フォームの代わりに送信処理をSPのリストに対して発火できる。

(例)
ボタン コンポーネント SendButton に、SharePoint リスト posts に対するフォームの送信処理を実装します。

SendButton.onSelect = Patch(
    posts,
    Defaults(posts),
    {
        sender: "sender",
        content: "aaaaaaaa"
    }
)
ARGIAARGIA

#SharePoint
created_at 的なメタ情報程度なら SP 側で勝手に生成してくれるようなので、こちらでスキーマとして準備する必要はない。デフォルトでは非表示になっているので表示設定が必要なことも付せて。

ARGIAARGIA

#PowerApps
ボタンの有効・無効化はプロパティ DisplayMode で指定する。

(例)
ボタン コンポーネント SendButton についてボタンを有効・無効にします。ここでは、チェックボックス コンポーネント ConfirmCheck も実装されています。

If(
    ConfirmCheck.Checked,
    DisplayMode.Edit,     // if true
    DisplayMode.Disabled  // if false
)

https://tsuchirikienrich.com/powerapps/botanno.html

ARGIAARGIA

#与太話
見ての通り、コンポーネントに対するプロパティの指定はほぼ Excel である。オブジェクト指向と Excel の即値的パラダイムが混ざって大変気持ち悪い。

ARGIAARGIA

#PowerApps
チェックボックスのチェック状況は CheckBox.Checked で取得できる。

ARGIAARGIA

#PowerApps
モダン コントロールとクラシック コントロールについては、要件が許すならモダンにするべきだと考えられる。モダンのほうではアクセシビリティやUXがクラシックに比べて改善されている。

ARGIAARGIA

#与太話
要調査事項:

  • 取得・表示するデータをユーザの権限によって変化させる方法。Power Apps単体ではおそらく不可能なため、Automateを用いることになるが知見がまったくない。
  • ポップアップウィンドウの実装。コンポーネントで呼び出せばいいらしいが、インタフェースの操作を考えるとどの記事も詰めが甘い[1]。でも参考にはしたい。
  • Dataverseのデータ格納について。データ型にJSONを許容して、しかもスキーマを設定できるなら大したものだがそこまで期待はできない。万が一リレーショナルなテーブルしか実装できないなら、SPのリストと大差はない。
脚注
  1. 別画面に遷移させるものに至っては、それはそもそもポップアップですらない。 ↩︎

ARGIAARGIA

#与太話
現在Dataverseが権限不足でアクセスできない状況に陥っている。神様助けて。

ARGIAARGIA

#与太話
dataverse は自明に universe をもじった単語である。じゃあ data はともかく -verse って何?ってなるじゃん。なるんですよ。なって。

そもそも univeseuni--verse に分解できます。uni はラテン語で「1」程度の意味です。そして verse はつまるところ versus に行き着くらしいんですよ。一つに絡みつくみたいなイメージかな?

じゃあ何、-verse はそういうことなの、対立 versus ってことなの?っていうと現代英語の接辞用法的にはまた違うみたいなんです。結論から言うと、-verse は「特定の要素全体を示す」働きをする接辞になりました。だから、dataverse は「データ全体」ぐらいの意味を指す複合名詞ってわけですね。

これで今日からあなたも dataverse[1] マスター。

脚注
  1. not “Dataverse” ↩︎

ARGIAARGIA

#PowerApps
Patch vs Collect

Patch 関数には以下のメリット・デメリットがあります。

  • 1件のデータを登録する時には結果が戻り値として帰ってくるので使いやすい
  • Patch 内で起こったエラーを拾える
  • 大量のデータを入れると時間がかかる or そもそもできない
  • 公式のサンプルアプリでは Patch が使われている

Collect 関数には以下のメリット・デメリットがあります。

  • 複数のデータを登録する時は高速
  • 公式のサンプルアプリでは使われていない
  • 戻り値が基本的にテーブル型で帰ってくるため、Firstなどの関数を使う必要がある
  • エラーが拾いにくい

https://qiita.com/taku_maru/items/b74ea60cafbb7d34ceac

ARGIAARGIA

#PowerApps

リッチテキストエディタからテキストを取得するときは次のようにする。形式はHTMLで固定となる。

(例)
リッチテキストエディタ コンポーネント Editor から入力データを取得します。

Editor.HTMLText
ARGIAARGIA

#PowerApps
ドロップダウンの扱いは謎。即値で選択肢をご用意いただかないで変数から注入しろっていうのはわかる。その変数はどこで定義するんですか?

ARGIAARGIA

#PowerApps
グローバル変数の宣言は実にフリーダムであり、適当なところで Set(name, value) すればよいらしい。
どう考えても無秩序に陥るが、グローバル変数は App オブジェクトの OnStart で宣言すると制約すればそれで済みそう。

ARGIAARGIA

#PowerApps
Power Fx で実装される関数 Set() は、Power Apps においては全画面共通で参照・更新できるグローバル変数と同じである。同実装上の関数 UpdateContext() は特定画面でのみ用いられるローカル変数である。思うにこれはローカルというよりコンテキスト(文脈)と解釈したほうが見通しが良くなるかもしれない。

https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-set
https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-updatecontext

ARGIAARGIA

#PowerApps
関数 Patch の戻り値を見て、成功の可否でダイアログを出したいな~って思いません?

ARGIAARGIA

#PowerApps
関数 Navigate() は、

  • 第二引数に画面遷移のエフェクト
  • 第三変数に次の画面に与えるコンテキスト変数

を指定できる。

(例)
画面 コンポーネント scrMainscrNextPage があります。scrMain に実装されたボタン コンポーネント btnProceed を押すと、scrNextPage に遷移したうえで、コンテキスト変数 ctxEmailctxPassword を与えます。また scrMain にはテキストボックス コンポーネント txtEmailtxtPassword が実装されています。

btnProceed.onSelect = Navigate(
    scrNextPage,
    UnCover,
    {
        ctxEmail: txtEmail.Text,
        ctxPassword: txtPassword.Text
    }
)
ARGIAARGIA

#PowerApps
ページ遷移は大体わかった。Back() のページ遷移エフェクトは、来た時が Uncover だったら自動的に UncoverRight になったりするんですかね?

ARGIAARGIA

#PowerApps
Power Apps / Power Fx 両仕様にハッシュ関数の類はないという報告を受けた。マジで?
ログイン処理とか当然挟むけど、ソルトはおろかハッシュでやり取りできないなら平文でやるしかない?

ARGIAARGIA

#Power Apps
テキストボックスをパスワードボックス化するには次の手順を踏む。

(例)テキスト入力 コンポーネント txtPassword を定義します。このコンポーネントに入力された文字は適切にマスクされるほか、パスワードの取り扱いに関する情報をブラウザに提供します。

txtPassword.Mode = TextMode.Password
ARGIAARGIA

#与太話
明日やること:

  • SharePoint のリストからユーザ名・パスワードを取得して認証を行う。
  • 別のリストを適当なスキーマで定義したうえで、データの追加・参照・更新・削除機能[1]を実装する。
脚注
  1. Create, Read, Update, Delete で、総称して CRUD と呼ばれるもの。 ↩︎

ARGIAARGIA

#PowerApps
必要であれば、Power Apps Studio の左のペインにある「変数」グループ((x))から各画面に定義されたコンテキスト変数およびアプリ全体のグローバル変数を参照できる。

ARGIAARGIA

#PowerApps
テキストボックスなどの入力データを削除したいときは、関数 Reset() を用いるとよい。

(例)
テキスト入力 コンポーネント txtUsername に入力されたユーザ名と txtPassword に入力されたパスワードを消去します。消去するタイミングは画面が表示されたとき、すなわち、イベント OnVisible が発火したときです。

Reset(txtUsername);
Reset(txtPassword);
ARGIAARGIA

#PowerApps
同一数式内で複数の処理を(直列に)実行するときは、セミコロン ; で命令を区切る。例は上記の通り。

ARGIAARGIA

#与太話
依然としてドロップダウンの選択肢候補を変数を経由して定義する方法が判明していない。

ARGIAARGIA

#PowerApps
SharePoint からリストを持ってきて表示するには Gallery コンポーネントが使える。選択内容を取ってくるにはオブジェクト内部(.Selected)にあるテキストテキストコンポーネントの Text プロパティをたたけばよい。

ARGIAARGIA

#PowerApps
ギャラリーの Default に与える要素(すなわちアプリを開いたときに最初に選択される項目)は LookUp() だかで仕入れてきたレコードで OK っぽい。ギャラリーの要素の中で仕入れてきた要素に一致するものがあれば、そのギャラリー要素がデフォルトで選択されることになる。

ARGIAARGIA

#SharePoint
ところで SPO の列を一意にしたかったり必須にしたり型を変えたかったら、SPOリストの右上歯車→リストの設定からいい感じに設定できる。

ARGIAARGIA

#PowerApps
「データソースに当該データが存在しない」という表現は IsBlank()LookUp() を用いればよい。

(例)
ボタン コンポーネント btnSend にレコードの存在の有無を通知する機能を実装します。スクリーンにはテキスト入力 コンポーネント txtId が存在しており、これにはユーザーの ID が入ります。btnSend はユーザーの ID を基準にデータソースを走査し、存在の有無をバナーで利用者に通知します。

btnSend.OnSelect = If(
    IsBlank(LookUp(source, id=txtId)),
    Notify("The record doesn't exist"),
    Notify("The record exists")
)
ARGIAARGIA

#PowerApps
いわゆる Upsert をしたい場合は、やはり Patch() を用いるとよさそう。ただし、データが既に存在する場合と存在しない場合で切り分けて処理しないとエラーが発生するっぽい?要検証。

例の説明文を書くのがめんどくさくなってきた。

UpdateContext({
    locUser: LookUp(source, id=txtId)
});

IfError(
    Patch(
        source,
        If(
            IsBlank(locUser),
            Defaults(posts),
            locUser
        ),
        {
            id: txtId,
            contents: "..."
        }
    ),
    Notify("FAIL", NotificationType.Error),
    Notify("SUCCESS", NotificationType.Success)
);
ARGIAARGIA

#PowerApps
Excel でいうところ IFS() は Power Fx では Switch() 関数になっている。構文は驚くほどクリソツで、なんで IFS() にしなかったのか不思議に思うぐらいには同じ。

Switch(expr, cond1, result1, [cond2, result2, [cond3, result3, [...]]], default) としたとき、expr は最初の一回のみ実行されたうえで、cond1, cond2 との照合が行われる。完全一致であれば、添字が一致する result (e.g. cond1result1)を返り値とする。一致する候補がなかったときは最後の default を返り値とする。

ARGIAARGIA

#PowerApps
ギャラリーコンポーネントの要素は Items プロパティに与える値をいじれば制御できる。
デフォルトでは gryComponent.Items = datasource であるが、ここで datasourceFilter 関数などに渡せば動的に表示要素を制御できる。

注意:見た目の上での制御となると考えられる。権限ベースで動いているわけではないので、やろうと思えば非表示項目もアプリ内部からデータを持ってくることは可能だと推測される。

ARGIAARGIA

#SharePoint
Power Apps に連携している SPO のリストがあったとして、アプリを配布したらそのリストの内容もアプリの配布先に筒抜けになっちゃうのかな?要検証。

ARGIAARGIA

#PowerApps
なんでか知らんが、選択肢(ドロップダウンコンポーネントだかSPOのリスト列だか)の内容は Power Apps 内部では drpComponent.Selected.Value としなければエラーが出る。.Selected で十分だと思うんだけど。

ARGIAARGIA

#PowerApps
フォームコンポーネントの扱いは非常に面倒くさいけれど、細やかな調整が不可能になった代償にかなり実装の手間を省けてとても便利ではある。

フォームコンポーネントを設置したら Dataverse なり SPO のリストなどに接続する。後は外界からボタンの OnSelect イベントなどで所定の関数を実行すればよい。所定の関数は次の四つである。なお、すべて唯一の引数として操作対象となるフォームのオブジェクトを受け取る。

  1. NewForm - 対象フォームを新規入力ができる形で初期化する。
  2. EditForm - 対象フォームの Item プロパティについて編集ができる形で初期化する。
  3. ViewForm - 〃について閲覧のみできる形で初期化する。
  4. ResetForm - 対象フォームをまっさらな形に初期化する。

https://learn.microsoft.com/ja-jp/power-apps/maker/canvas-apps/working-with-form-layout
https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-form

ARGIAARGIA

#PowerApps
フォームに見出しなどを追加したい場合は、「カスタムカード」を代理に挿入したうえで、カスタムカード内にラベルなどを設置する。この場合レスポンシブ配置は作動しないので、レイアウトは完全に手動である。なんだこれ?

ARGIAARGIA

#Dataverse
Unique Constraint は効かないっぽいので、代替キー(Alternative Key)なるものを用いなければならないかも。
https://learn.microsoft.com/ja-jp/power-apps/developer/data-platform/define-alternate-keys-entity

ARGIAARGIA

テーブルの概要を開いて、スキーマの「キー」→「新しいキー」であとは適当に列を選択すれば代替キーが出来上がる。複合キーにしたいなら列を複数選択する。

このときキー名は何でもいいっぽいけど、pk とか ak とかそんなふうにしたほうがいいんだろうか。

ARGIAARGIA

#dataverse
1件の最小セットをDVにインポートさせると、なんと3000件完全に空であるレコードがついでに挿入される。二回やると8000件、三回目は1.3万件・・・ひどい・・・

ARGIAARGIA

同僚を頼ったらそちらの環境ではうまくいき、自環境でも正常に動作することが確認できた。何故?

ARGIAARGIA

#dataverse
選択肢を型として宣言できるんだけど、選択肢を機械的に注入する方法がない。
そのせいで、300個ぐらいの選択肢がある列を作るとき、300個ぐらいの選択肢をスキーマを作るときにチマチマ入れていかないといけない。非現実的だ。

ARGIAARGIA

SPOだと概ねうまくいく。SPOも機械的に注入する方法はないが、テキストボックスに行単位で候補を入れるだけなのでだいぶ気が楽。

ARGIAARGIA

#PowerApps
モダンコントロールはバグっていて、クラシックなほうで動く挙動がモダンだと動かない例を発見した。

(事例)
クラシック・モダン両方のドロップダウンコントロールを用意して、Items = Distinct(source, row) とする。クラシックなほうは列名もとい選択値が表示されるが、モダンなほうは選択肢が表示されないときがある。外部からテキストラベル経由で選択値を持ってくると正当なデータが返ってくるため取得自体はうまくいっているが、レンダリングがダメ。

ARGIAARGIA

#PowerApps
テーブルとレコードと配列宣言の違いがいまだによくわからない。Power Fx は配列すら宣言できないように見えるし、配列で渡せばいいところをわざわざテーブル(多分連想配列)で渡さないといけなかったりして非常に保守性が悪い。

ARGIAARGIA

#PowerApps
モダンコントロールでもいつの間にテーマ制御ができるようになっていた。
細かい色の指定は無理だが、色調を要件に寄せるぐらいのことはできる。

このスクラップは2023/10/26にクローズされました