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 manualePer far questo è necessario avere una lista
SharePoint o tabella
SQL con un campo
numerico intero, ad esempio di nome
Position.
Lista SharePointLa
Gallery dovrà avere 2 pulsanti
up e
down
Pulsanti di spostamentocon ad esempio questa formula come query sui dati:
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:
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
_MoveUpUpdateContext(
{
_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à:
gallerySxIcnUp.OnSelect =
UpdateContext({_MoveUp: "up"});
Select(Parent); /* richiamo l'evento Gallery.OnSelect */
quello
downgallerySxIcnDown.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
Gallery.OnSelect =
If(_MoveUp ="up" Or _MoveUp = "down",
/* move */
...,
/* else */
...
);
Il codice completo della
Gallery.OnSelect sarà
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:
gallerySxIcnUp.DisplayMode = If(First(FirstN(SortByColumns(TodoList, "Position", Ascending),1)).ID = ThisItem.ID, DisplayMode.Disabled, DisplayMode.Edit)
mentre quello
down userà
LastN:
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)).