PowerApps│感謝を送り合う社内SNSアプリの作り方 ③いいね機能とコレクション

こんにちは、あんこ先生です。

前回は、投稿がずらっと並ぶタイムライン画面を作りました。

見るだけの画面から、今回は反応できる画面にしていきましょう。

そう、いいね機能です。

一度押したら青くなって、もう一度押すと取り消せる。あのトグルを作ります。

この記事で作るもの
・投稿ごとのいいねボタン(アイコン+件数)
・押すと付いて、もう一度押すと外れるトグル
・同じ人が二重にいいねできない仕組み

まだ読んでいない人は、先にタイムライン画面の回を作っておいてくださいね。

いいねの仕様を決めておく

コードを書く前に、動きをはっきりさせておきましょう。

・ひとりが同じ投稿に押せるのは1回だけ
・もう一度押したら取り消せる
・投稿ごとに、いま何件いいねが付いているか出す

この「1回だけ」というのが、地味に考えどころです。

ボタンを押した回数を数えるだけなら簡単なのですが、それだと同じ人が連打できてしまいますからね。

データの持ち方をおさらい

第1回で作った Likes リストを思い出してください。

列は PostID ひとつだけ、という驚くほどシンプルなリストでした。

入るもの
PostIDどの投稿へのいいねか
登録者誰が押したか(SharePointが自動で記録)

「誰が押したか」は 登録者 が勝手に入るので、列を足す必要がありません。

つまり「この投稿IDで、この人の行があるか」を調べれば、いいね済みかどうかが分かる、というわけです。

いいねを押したら1行足す。取り消したらその行を消す。それだけです。

まず「自分がいいね済みか」を調べる

さて、ここからが本番です。

タイムラインの各行で「自分はこの投稿にいいねしたっけ?」を判定したいわけですが、行ごとに毎回Likesを調べにいくと、行の数だけ問い合わせが走って重くなります。

そこで、画面を開いたときに、自分がいいね済みの投稿IDをまとめて取ってきておきます。

画面 scrTimelineOnVisible に、こちらを入れてください。

//画面 scrTimeline の OnVisible(自分がいいね済みの投稿IDをまとめて取得する)
//各行で毎回 Likes を調べるより軽く、委任の警告も避けやすい
ClearCollect(
    colMyLikes,
    ForAll(
        Filter(Likes, Author.Email = User().Email),
        { Value: PostID }
    )
)

Likesを「自分が登録した行」だけに絞って、その PostIDcolMyLikes に並べています。

ここで、ひとつ大事なところがあります。

ForAll でわざわざ { Value: PostID } という形に詰め替えているところです。

ForAll そのものの使い方は、繰り返し処理ならコレ!ForAll関数の便利な使い方にまとめてあります。

なぜ列名を Value にするのか

素直に書くなら、こうしたくなりますよね。

//一見よさそうだけど、あとで困る書き方
Filter(Likes, Author.Email = User().Email).PostID

これでも投稿IDだけが並んだ入れ物にはなります。

ただし、このときの列名は PostID です。

いっぽう、あとでいいねを押したときには、コレクションにも1件足しますよね。

そこで Collect を使うと、列名を自分で決めることになります。

ここで { Value: … } と書いてしまうと、最初に作った列名(PostID)と食い違ってしまうんですね。

ここが落とし穴:列名は4か所でそろえる
コレクションを使うときは、次の4か所で列名がそろっている必要があります。
・作るとき(ClearCollect)
・調べるとき(in で判定)
・足すとき(Collect)
・消すとき(RemoveIf)

ひとつでも違うと、足したぶんだけ判定から外れて「押したのに色が変わらない」といった動きになります。値をひとつだけ並べる入れ物は、列名を Value にそろえておくのが慣例です。迷ったら Value、と覚えておくとラクですよ。

コレクションの作り方や加工の仕方をおさらいしたい人は、複写!抽出!追加!結合!コレクションの加工方法もどうぞ。

いいねボタンを置く

では、ギャラリーの中にボタンを追加しましょう。

モダンボタンを置いて、名前を btnLike にします。

プロパティ設定する式
Icon“ThumbLike”
TextText(ThisItem.LikeCount)
LayoutButtonLayout.IconBefore
AppearanceButtonAppearance.Transparent
Height32
Width90
X86
YimgPost.Y + imgPost.Height + 6

LayoutIconBefore にすると、アイコンの右に文字が並びます。

そこに件数を出しているので、「👍 3」のような見た目になりますね。

Y座標は、前回おぼえた「ひとつ上の下端から積む」を守っています。

状態は色で表す

いいね済みかどうかを、見た目でも分かるようにしましょう。

Color にこちらを入れます。

//いいねボタン btnLike の Color(いいね済みなら青、まだならグレー)
If(ThisItem.PostID in colMyLikes.Value, RGBA(0, 120, 212, 1), RGBA(120, 120, 120, 1))

さっき作った colMyLikes の出番です。

in は「その中に含まれているか」を調べる演算子で、ここでは「この投稿IDが、自分のいいね済み一覧に入っているか」を見ています。

ここが落とし穴:塗りつぶしのアイコンは無い
SNSでよくあるのは、押すとアイコンが線画から塗りつぶしに変わる表現ですよね。ところがモダンボタンには、いいねの塗りつぶし版アイコンがありません。用意されているのは “ThumbLike”(親指)と “Heart”(ハート)で、どちらも線画だけです。なので、塗りと線で切り替えるのはあきらめて、色で状態を出しています。ちなみにアイコン名は文字列で指定します。クラシックのアイコンのように Icon.ThumbLike と書くとエラーになるので気をつけてください。

モダンボタンのプロパティは、モダンコントロール ボタン(Button)の使い方にもまとめてあります。

押したときの処理を書く

いよいよ本丸です。

OnSelect に、こちらを入れてください。

//いいねボタン btnLike の OnSelect(押すたびに、いいねを付けたり外したりする)
//すでに押していれば取り消し、まだなら追加する
//画面をひらき直さなくても見た目が変わるよう、コレクションも同時に更新する
If(
    ThisItem.PostID in colMyLikes.Value,

    RemoveIf(Likes, PostID = ThisItem.PostID, Author.Email = User().Email);
    Patch(Posts, ThisItem, { LikeCount: ThisItem.LikeCount - 1 });
    RemoveIf(colMyLikes, Value = ThisItem.PostID),

    Patch(Likes, Defaults(Likes), { Title: ThisItem.PostID, PostID: ThisItem.PostID });
    Patch(Posts, ThisItem, { LikeCount: ThisItem.LikeCount + 1 });
    Collect(colMyLikes, { Value: ThisItem.PostID })
)

長く見えますが、やっているのは3つずつの作業を、2パターン書いているだけです。

Patch の基本を確認したい人は、Patch関数の使い方 基本編を先に読んでおくと分かりやすいですよ。

すでに押していたら(取り消し)

やること使う関数
Likesから自分の行を消すRemoveIf
投稿のいいね数を1減らすPatch
コレクションからも消すRemoveIf

RemoveIf の条件がふたつ並んでいるのがポイントです。

「この投稿の行」かつ「自分が登録した行」に絞ることで、ほかの人のいいねを巻き込まずに済みます。

まだ押していなかったら(追加)

やること使う関数
Likesに自分の行を足すPatch
投稿のいいね数を1増やすPatch
コレクションにも足すCollect

こちらも同じ3点セットで、向きが逆になっただけですね。

ひとことメモ:Titleに何を入れているの?
Likesに行を足すとき、Title にも投稿IDを入れています。第1回でTitleの必須は外したので、空のままでも登録できます。ただ、SharePointのリスト画面で中身を見たときに、Titleが空だと何の行なのかさっぱり分からないんですね。あとから自分が困らないよう、目印として入れてあります。

なぜコレクションも一緒に更新するのか

Likesへの登録だけなら、SharePointの側は正しくなります。

でも、画面の色を決めているのは colMyLikes のほうでしたよね。

ここを更新しないと、押したのに色が変わらない、という残念な動きになってしまいます。

そこで、SharePointとコレクションの両方を同時に更新しているわけです。

LikeCount のほうは、Patch で投稿そのものを更新しているので、件数の表示もその場で変わります。

区切り線の位置を直す

最後にひとつ、前回作った部分に手を入れます。

いいねボタンが画像の下に入ったので、区切り線 recDivider はその下にずらしましょう。

プロパティ変更前変更後
YimgPost.Y + imgPost.Height + 16btnLike.Y + btnLike.Height + 12

これで、いちばん下の部品がまた区切り線に戻りました。

前回の「ドミノ倒し」の話を思い出してもらえると、なぜこの1行を直すだけで行の高さが正しくなるのか、すっと入ってくるはずです。

知っておきたいこと

動くようになったところで、この作りの性格も押さえておきましょう。

ほかの人のいいねは、すぐには映らない

colMyLikes は、画面を開いた時点のものです。

そのため、自分が押したぶんはその場で反映されますが、ほかの人が同じタイミングで押したいいねは、画面を開き直すまで出てきません。

部署内で25人ほどの利用なら、これで困ることはまずないと思います。

気になるようなら、更新ボタンを置いて OnVisible と同じ式を実行する、という手もありますね。

委任の警告が出たら

登録者 のようなユーザー列をメールアドレスで絞ると、委任の警告(青い下線)が出ることがあります。

これは「データが増えたときに、全部を正しく調べられないかもしれません」という注意書きです。

数千件を超えると影響が出てきますが、部署内のサンクスアプリならしばらくは平気でしょう。

委任そのものについては、黄色いアイツ、委任警告の回避方法でくわしく解説しています。

まとめ

今回はここまでにしましょう。

・「1人1回」は、LikesにPostID登録者の行があるかどうかで判定する。
・行ごとに調べにいかず、画面を開いたときに colMyLikes へまとめて取っておく。
・値をひとつ並べるコレクションは、列名を Value にそろえる。作る・調べる・足す・消すの4か所ぜんぶ。
・いいねを押したら、SharePointとコレクションの両方を更新する。片方だけだと見た目が付いてこない。

次の一手として、次回はいよいよ投稿画面を作ります。

アプリの中から「ありがとう」を送れるようにする回ですね。

送信先を選んで、メッセージを書いて、タグを付けて、画像も添える。

ここまで作ると、ようやくアプリの中だけで一周できるようになりますよ。

それでは、次の記事でお会いしましょう。

ABOUT US
七草あんこ
非IT系中間管理職やってます。社命によりoffice365を主軸とした業務改善プロジェクトメンバーに任命されたことでPowerAppsと出会えました。いまではビジネス・プライベートを問わず、欠かせないツールになっています。導入初期やアプリ作成時に遭遇した諸問題の解決法とサンプルアプリの作り方を紹介していきます。主にTwitterで情報収集しているので不明点など呟いているとお邪魔するかもしれません。