Può capitare di dover gestire in Power Apps un ordinamento manuale in una lista, ad esempio, in una Todo list, si può voler definire una diversa priorità degli elementi da gestire tramite appositi pulsanti di spostamento su e giù.
Ordinamento manuale
Ordinamento manuale
Per far questo è necessario avere una lista SharePoint o tabella SQL con un campo numerico intero, ad esempio di nome Position.
Lista SharePoint
Lista SharePoint
La Gallery dovrà avere 2 pulsanti up e down
Pulsanti di spostamento
Pulsanti di spostamento
con ad esempio questa formula come query sui dati:

Power Apps

Gallery.Items= SortByColumns(TodoList, "Position", Ascending)
E' fondamentale che l'ordinamento sia fatto sul campo Position.

Lo spostamento andrà realizzato tramite il metodo RowNumber associando il seguente codice di spostamento nell'evento OnSelect dei pulsanti:

Power Apps

UpdateContext(
    {
        _MoveUp: "up", /* impostare "down" per scendere */
        _FirstRowNumber: 0,
        _FirstID: ThisItem.ID
    }
);

/* salvo la query di ordinamento basata sul campo Position, deve coincidere con quella impostata nella Gallery.Items */
ClearCollect(
    _TmpTable,
    SortByColumns(
        TodoList,
        "Position",
        Ascending
    )
);

/* creo una nuova lista ordinata con RowNumber sequenziale/progressivo e l'ID riga */
Clear(_TableRowNumber);
ForAll(
    _TmpTable,
    Collect(
        _TableRowNumber,
        Last(
            FirstN(
                AddColumns(
                    ShowColumns(
                        _TmpTable,
                        "ID",
                        "Position"
                    ),
                    "RowNumber",
                    CountRows(_TableRowNumber) + 1
                ),
                CountRows(_TableRowNumber) + 1
            )
        )
    )
);

/* faccio pulizia di quello che non serve più */
Clear(_TmpTable);

/* trovo la riga corrente */
UpdateContext(
    {
        _FirstRowNumber: LookUp(
            _TableRowNumber,
            ID = _FirstID
        ).RowNumber
    }
);

/* e quella successiva o precedente */
UpdateContext(
    {
        _SecondRow: LookUp(
            _TableRowNumber,
            RowNumber = _FirstRowNumber + If(
                _MoveUp = "up",
                -1,
                1
            )
        )
    }
);

/* procedo con lo scambio ed aggiorno il db/lista */
If(
    IsBlank(_SecondRow) = false,

    /* scambio */
    Patch(
        _TableRowNumber,
        LookUp(
            _TableRowNumber,
            ID = _FirstID
        ),
        {RowNumber: _SecondRow.RowNumber}
    );
    Patch(
        _TableRowNumber,
        LookUp(
            _TableRowNumber,
            ID = _SecondRow.ID
        ),
        {RowNumber: _FirstRowNumber}
    );

    /* aggiorno i valori sul DB */
    ForAll(
        _TableRowNumber,
        If(
            _TableRowNumber[@Position] <> _TableRowNumber[@RowNumber],
            /* aggiorno solo se sono cambiati rispetto all'esistente */
            Patch(
                TodoList,
                LookUp(
                    TodoList,
                    ID = _TableRowNumber[@ID]
                ),
                {Position: _TableRowNumber[@RowNumber]}
            )
        );
    );
);

/* faccio pulizia di quello che non serve più */
Clear(_TableRowNumber);
UpdateContext(
    {
        _MoveUp: "",
        _SecondRow: Blank()
    }
);
Visto che la colonna Position potrebbe contenere dei valori non consecutivi o duplicati a causa di interventi manuali sulla lista, come prima cosa creo una collection temporanea _TableRowNumber ordinata per Position con l'aggiunta di una colonna RowNumber contentente un numero pregressivo che parte da 1.

A questo punto, partendo dalla riga corrente, è sufficiente scambiare i RowNumber con la riga precedente (move up) o successiva (move down), in base al pulsante premuto.

In ultimo salvo i valori di RowNumber sulla campo Position della lista/tabella.
Attenzione il sistema proposto funziona bene su liste con poche decine elementi, pena un calo delle prestazioni.
Nel caso del pulsante di spostamento in giù (down), copiare il codice e cambiare l'impostazione delle variabile _MoveUp

Power Apps

UpdateContext(
    {
        _MoveUp: "down",
        _FirstRowNumber: 0,
        _FirstID: ThisItem.ID
    }
);
...

Metodo alternativo

Anziché duplicare lo stesso codice nei due pulsanti up e down, si può mettere il codice in un unico punto sull'evento Gallery.OnSelect e nei pulsanti up e down impostare solo una variabile.

A questo punto il pulsante up conterrà:

Power Apps

gallerySxIcnUp.OnSelect = 
UpdateContext({_MoveUp: "up"}); 
Select(Parent);  /* richiamo l'evento Gallery.OnSelect */
quello down

Power Apps

gallerySxIcnDown.OnSelect = 
UpdateContext({_MoveUp: "down"}); 
Select(Parent)
infine Gallery.OnSelect conterrà una If che gestirà gli eventi move (up/down) oppure (else) gli altri eventi della riga

Power Apps

Gallery.OnSelect =
If(_MoveUp ="up" Or _MoveUp = "down",
    /* move */
    ...,
    /* else */
    ...
);
Il codice completo della Gallery.OnSelect sarà

Power Apps

If(
    _MoveUp = "up" Or _MoveUp = "down",
    /* move */
    UpdateContext({_FirstID: ThisItem.ID});

    /* salvo la query di ordinamento basata sul campo Position */
    ClearCollect(
        _TmpTable,
        SortByColumns(
            TodoList,
            "Position",
            Ascending
        )
    );
    
    /* creo una nuova lista ordinata con RowNumber sequenziale/progressivo e l'ID riga */
    Clear(_TableRowNumber);
    ForAll(
        _TmpTable,
        Collect(
            _TableRowNumber,
            Last(
                FirstN(
                    AddColumns(
                        ShowColumns(
                            _TmpTable,
                            "ID",
                            "Position"
                        ),
                        "RowNumber",
                        CountRows(_TableRowNumber) + 1
                    ),
                    CountRows(_TableRowNumber) + 1
                )
            )
        )
    );
    
    /* faccio pulizia di quello che non serve più */
    Clear(_TmpTable);
    
    /* trovo la riga corrente */
    UpdateContext(
        {
            _FirstRowNumber: LookUp(
                _TableRowNumber,
                ID = _FirstID
            ).RowNumber
        }
    );
    UpdateContext(
        {
            _SecondRow: LookUp(
                _TableRowNumber,
                RowNumber = _FirstRowNumber + If(
                    _MoveUp = "up",
                    -1,
                    1
                )
            )
        }
    );
    
    /* procedo con lo scambio ed aggiorno il db/lista */
    If(
        IsBlank(_SecondRow) = false,
        /* scambio */
        Patch(
            _TableRowNumber,
            LookUp(
                _TableRowNumber,
                ID = _FirstID
            ),
            {RowNumber: _SecondRow.RowNumber}
        );
        Patch(
            _TableRowNumber,
            LookUp(
                _TableRowNumber,
                ID = _SecondRow.ID
            ),
            {RowNumber: _FirstRowNumber}
        );
        /* aggiorno i valori sul DB */
        ForAll(
            _TableRowNumber,
            If(
                _TableRowNumber[@Position] <> _TableRowNumber[@RowNumber],
                /* aggiorno solo se sono cambiati rispetto all'esistente */
                Patch(
                    TodoList,
                    LookUp(
                        TodoList,
                        ID = _TableRowNumber[@ID]
                    ),
                    {Position: _TableRowNumber[@RowNumber]}
                )
            );
        );
    );
    /* faccio pulizia di quello che non serve più */
    Clear(_TableRowNumber);
    UpdateContext({_SecondRow: Blank()});
    ,
    /* else*/
    ...
);
/* resetto la variabile con l'evento */
UpdateContext({_MoveUp: ""});
Attenzione è importante alla fine resettare la variabile _MoveUp.

Gestione abilitazione pulsanti

Idealmente il pulsante up sulla prima riga dovrebbe essere disabilitato così come il pulsante down nell'ultima riga.

Per far questo si può gestire la proprietà DisplayMode confrontando gli ID della prima e ultima riga nella Gallery.

Il pulsante up userà l'istruzione FirstN:

Power Apps

gallerySxIcnUp.DisplayMode = If(First(FirstN(SortByColumns(TodoList, "Position", Ascending),1)).ID = ThisItem.ID, DisplayMode.Disabled, DisplayMode.Edit)
mentre quello down userà LastN:

Power Apps

gallerySxIcnDown.DisplayMode = If(First(LastN(SortByColumns(TodoList, "Position", Ascending),1)).ID = ThisItem.ID, DisplayMode.Disabled, DisplayMode.Edit)
anche in questo caso devo va usata la stessa formula della proprietà Gallery.Items (SortByColumns(TodoList, "Position", Ascending)).
Tags:
Power Apps26 SharePoint Online75 SQL Server100
Potrebbe interessarti anche: