コルネの進捗や備忘録が記されたなにか

進捗や成果物や備忘録てきななにかを雑に更新していきます。

Power Appsでアイテムの順番を変更する


スポンサードリンク

はじめに

Power Appsでアイテム(コレクション)の表示順を変更する方法をまとめています。

こんな感じのドロップダウンで、ソート順を変更するイメージです。

ドラッグ & ドロップでいい感じに順番を変更する方法は紹介していないのでご留意ください。

今回サンプルで用意したコレクション

紹介を行うにあたり用意したコレクションは以下です。

ClearCollect(
    col,
    ForAll(
        Sequence(10),
        {
            _guid: GUID(),
            Index: ThisRecord.Value,
            num: ThisRecord.Value,
            char: Char(ThisRecord.Value + 64)
        }
    )
)
フィールド名 役割
_guid 行を一意に特定するためのフィールドです
Index コレクションの並び順を特定するためのフィールドです
その他 行の値です(numやchar)
ここはなんでもOK

並び順を変更するにはなにをする必要がある?

例えば1~5の数字があったとして、"3"を一番上に持ってくるとします。

その場合、順番が変更になるのは"1"、"2"、"3"の3つですね。

このように順番を変更するためには、変更を行う自分自身及びそれに関連する他のアイテムまで変更が必要になってきます。

そのことを意識したうえで実装を行っていきましょう。

なお、この後で紹介する式はすべてDropDownのOnChangeに記載しています。

[やり方その1]変更後の間に設定する

まず1つ目のやり方は、変更後の間にアイテムを設定するやり方です。

例えば並び順が1番目のアイテムを3番目に変更する場合、並び順が3番目と4番目の間に設定してあげればよいです。

つまり、3番目と4番目のIndex値の半分の値を設定してあげればいいですね。

続いて並び順が5番目のアイテムを2番目に変更する場合をみてみましょう。
この場合は、1番目と2番目の間に設定する必要がありますね。

このようにアイテムを上にもってくるのか下にもってくるのかによって、挿入する箇所が異なってくる。というのがこのやり方の場合の注意点です。

注意点は他にもあります。

それはアイテムを最初、もしくは最後に順番を変更する場合ですね。

最初に挿入する場合は最初の前のアイテムが、最後に挿入する場合は最後の次のアイテムが存在しません。
よって、"間に挿入する"という計算を行う際は仮の値を設定して計算する必要がでてきます。

これらの点に注意して式を設定すると以下のようになります。

UpdateIf(
    col, 
    _guid = ThisItem._guid, 
    {
        Index: 
            (
                Index(Sort(col, Index), Self.Selected.Value).Index + 
                Switch(
                    Self.Selected.Value,
                    1, 0,
                    CountRows(col), CountRows(col) + 1,
                    Index(Sort(col, Index), Self.Selected.Value + (Self.Selected.Value - ThisItem.Index) / Abs(Self.Selected.Value - ThisItem.Index)).Index
                )
            ) / 2
    }
);

1つめのアイテムを上にもってくるのか下にもってくるのかの判断は下のような式によって解決しています。

(Self.Selected.Value - ThisItem.Index) / Abs(Self.Selected.Value - ThisItem.Index)

上記式だと、上に持ってくる場合は"+1"が設定され、下に持ってくる場合は"-1"が設定されることになりますね。

2つめの最初と最後の条件はSwitch関数を使うことで解決しています。

最後に、Indexが小数で表されているとどこかで浮動小数点による計算誤差が発生する恐れがあるので整数に戻してあげます。

ForAll(
    Sort(col, Index) As tmpItems,
    UpdateIf(col, _guid = tmpItems._guid, {Index: CountIf(col, Index <= tmpItems.Index)})
)

一応これらをまとめた式の全体はこちらになります。

UpdateIf(
    col, 
    _guid = ThisItem._guid, 
    {
        Index: 
            (
                Index(Sort(col, Index), Self.Selected.Value).Index + 
                Switch(
                    Self.Selected.Value,
                    1, 0,
                    CountRows(col), CountRows(col) + 1,
                    Index(Sort(col, Index), Self.Selected.Value + (Self.Selected.Value - ThisItem.Index) / Abs(Self.Selected.Value - ThisItem.Index)).Index
                )
            ) / 2
    }
);
ForAll(
    Sort(col, Index) As tmpItems,
    UpdateIf(col, _guid = tmpItems._guid, {Index: CountIf(col, Index <= tmpItems.Index)})
)

考慮事項もそこそこあったので、あまりシンプルな式ではないですね。。。

[やり方その2]変更前のIndex値と変更後のIndex値を保持して並び替える

こちらの方法の方がシンプルで直感的だと思いますので、私はこちらの方法をおすすめします。

順番を入れ替える操作を行う場合、以下のような手順を行えば順番を入れ替えることができるかと思います。

  1. 対象のアイテムを入れ替え先のIndex値に設定する
  2. 対象のアイテムが下に移動する場合は、関連するアイテムのIndex値を1つ下げる
    対象のアイテムが上に移動する場合は、関連するアイテムのIndex値を1つ上げる

2つめの手順を実施する際は、1つめの手順で対象になったアイテムは除外してあげる必要がありますね。

このことに注意して式に起こすと以下のようになります。

With(
    {
        oldIndex: ThisItem.Index,
        newIndex: Self.Selected.Value,
        selectedItemId: ThisItem._guid
    },
    UpdateIf(col, _guid = selectedItemId, {Index: newIndex});
    If(
        oldIndex < newIndex,
        UpdateIf(col, _guid <> selectedItemId && Index > oldIndex && Index <= newIndex, {Index: Index - 1}),
        UpdateIf(col, _guid <> selectedItemId && Index < oldIndex && Index >= newIndex, {Index: Index + 1})
    );
)

式もシンプルでわかりやすいものになっているかと思います!

おわりに

並び順を変更したいなーというケースはよくあるかと思いますので、参考にしていただけると幸いです。  

不明点などあればコメントなどお気軽にどうぞー


スポンサードリンク