Introduzione
Spesso si sente la necessità di definire l'ordine sequenziale con cui, immagini, files, news o altro devono essere presentati all'utente di un sito web. Se si tratta di dati statici, e cioè dati inseriti manualmente nel markup
HTML di una pagina web, il problema non sorge, in quanto in fase di creazione della pagina, si definisce l'ordine con cui i nostri dati devono comparire.
Il problema sorge nel caso di dati che sono stivati in un database, e che all'occorrenza vengono presentati nella pagina web, magari in funzione delle azioni dell'utente navigatore. In questo caso le possibilità di ordinare la presentazione dei dati sono quelle offerte dalla modalità di ordinamento dei dati derivante dalla clausola
ORDER BY che utilizziamo nella query di selezione nel momento in cui andiamo a prelevare i dati dal nostro database. Qui troviamo uno schema chiuso che ci è dato da ordinamenti crescenti e decrescenti su ogni campo della tabella che contiene i nostri dati, ma nulla che possa permetterci di definire a nostro piacere un tipo di ordinamento che prescinda delle suddette preesistenti modalità di ordinamento crescente e decrescente.
La finalità è dunque quella di dare ai dati presenti in una tabella di un database un determinato tipo di ordinamento, e far si che gli stessi vengano presentati nella pagina web secondo l'ordine definito.
Questo strumento nasce dunque come supporto da utilizzare nei
CMS di siti web, da mettere al servizio dell'amministratore del sito.
Tecnologie impiegate
Il sistema è stato progettato e realizzato su piattaforma
ASP.NET 3.5 e con l'ausilio di un
Update Panel. Quest'ultimo componente gioca un ruolo molto importante in quanto grazie ad esso, (alla chiamata asincrona che effettua) il modulo acquisisce una elevata velocità di esecuzione senza la quale il modulo avrebbe delle difficoltà di utilizzo stante il continuo call-back server-client ad ogni azione di spostamento di una riga in basso o in alto, stante la necessità di salvare, ad ogni spostamento di riga, il nuovo ordine dato alle righe (record).
Il progetto
Presupposto di base all'utilizzo del modulo è l'esistenza di un database al servizio del sito web.
Il modulo progettato e realizzato poggia su di un database
MySql esistente su di un server web. Ma questo non è limitativo in quanto il sistema prescinde dal tipo di database utilizzato e può, con i dovuti aggiustamenti, essere utilizzato anche su altri DB.
Per poter implementare il modulo, è necessario l'ausilio
AJAX che per gli utenti che utilizzano la versione
2.0 del Framework .NET, va installato a parte; per l'installazione di AJAX il seguente link offrirà ogni dettaglio tecnico necessario:
Microsoft ASP.NET AJAX Per chi invece utilizza la versione
3.5 e successive del
Framework .NET, non c'è alcun bisogno di ulteriori installazioni dal momento che
ASP.NET AJAX è già contenuto in queste versioni del
Framework.NET.
La griglia dati completa
Di seguito si mostra, al fine di dare al lettore una prima idea di ciò che si sta andando a realizzare, uno screenshot del modulo completo. Così come è stato realizzato e posto on-line.
Sono evidenziati i pulsantini che permettono di spostare il singolo record/riga in basso o in alto e la colonna che indica il numero progressivo di ordinamento.
Inutile dire che il layout della griglia e dei pulsantini può essere gestito a piacimento secondo le proprie esigenze grafiche.
I controlli e gli oggetti necessari
Dopo essersi accertati che si dispone degli strumenti necessari si può procedere a costruire la pagina inserendo in essa i controlli
Per avviare la creazione della pagina destinata a contenere il modulo di riordinamento si eseguano i seguenti passi:
a) creare una pagina
ASP.NET destinata a contenere la griglia dati che permetterà l'ordinamento.
Nella pagina
ASP.NET si aggiungano i seguenti controlli:
1) un controllo
ScriptManager;
2) un controllo
UpdatePanel;
3) un controllo
GridView;
All'interno della griglia:
4) i pulsanti per eseguire lo spostamento della riga in basso o in alto che saranno dei “buttonFiled” della gridView;
5) una colonna destinata a contenere il progressivo di ordinamento.
Di seguito una serie di immagini a supporto per questa Operazione.
b) Selezionare il controllo
ScriptManager e trascinarlo sulla Pagina avendo cura di inserirlo nel tag <form> della pagina.
c) Selezionare il controllo UpdatePanel e trascinarlo nella pagina, posizionandolo al di sotto del Controllo
Script Manager.
d) Selezionare il controllo
GridView e collocarlo all'interno dell'
UpdatePanel;
e) Aggiungere Pulsanti all'interno della griglia. Questi dovranno essere dei
ButtonField. Il markup dei pulsanti, una volta collocati nella griglia, sarà pressappoco il seguente:
<asp:ButtonField ButtonType="Button" CommandName="SU" Text="SU" >
<ControlStyle Font-Size="7pt"></ControlStyle>
<ItemStyle Width="10px" />
</asp:ButtonField>
<asp:ButtonField ButtonType="Button" CommandName="GIU" Text="GIU" >
<ControlStyle Font-Size="7pt"></ControlStyle>
<ItemStyle Width="10px" />
</asp:ButtonField>
Come si può notare, per entrambi i pulsanti è stato definito l'attributo
CommandName. Questo valore viene utilizzato nell'evento
RowCommand della griglia per intercettare il tipo di operazione da eseguire, e cioè se si tratta di uno spostamento verso l'alto o verso il basso, all'interno della griglia.
f) La colonna ordine della griglia.
La colonna che ospita il progressivo dell'ordinamento svolge due funzioni:
1) Indica all'utente la posizione ordinale dell'item 3° posto, 4°, 12° posto etc. in modo che l'utente possa avere sempre una visione dei progressivi di ordinamento;
2) Questo valore viene prelevato dal codice server-side, ed utilizzato per rieseguire l'ordinamento ad ogni spostamento verso il basso o verso l'alto. Senza di questo, il sistema non saprebbe quale è la posizione corrente del record da spostare. E quindi non sarebbe in grado di riordinare correttamente gli Items.
Una volta creata la pagina, e collocati in essa i controlli necessari possiamo passare alla compilazione del codice lato server che provvederà a popolare la griglia, a spostare le righe in alto o in basso e a salvare i dati ogni qualvolta una riga viene spostata. E' inoltre necessario aggiungere alla tabella del database che contiene i dati a cui intendiamo dare il “Nostro” ordinamento, un campo numerico che contenga il progressivo di ordinamento. Questo campo oltre a contenere il numero di ordinamento, verrà utilizzato dalla query di selezione di lettura dei dati, come campo su cui impostare la clausola
ORDER BY in sede di renderizzazione dei dati a video.
Il Campo Ordinale
Affinché il modulo possa svolgere la sua funzione è necessario aggiungere alla tabella dei dati del Database un campo numerico destinato a contenere il numero ordinale dell'ordinamento che di volta in volta l'utente assegna ai dati.
Quindi aggiungiamo alla nostra tabella il campo di tipo intero che chiameremo "ordinale"
N.B. è necessario anche impostare nella tabella il campo id come numeratore progressivo univoco (il classico id che ogni record che si rispetti deve possedere). Anche questo dato deve essere riportato nella
GridView.
Per completezza si riporta il codice html della griglia destinata ad ospitare i dati:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
CssClass="Gridview1" PageSize="8" Font-Size="12px">
<Columns>
<asp:BoundField DataField="id" HeaderText="ID" >
<ItemStyle Width="5px" />
</asp:BoundField>
<asp:BoundField DataField="ordinale" HeaderText="Ordine" >
<ItemStyle Width="20px" />
</asp:BoundField>
<asp:BoundField DataField="nome" HeaderText="Nome" >
<ItemStyle Width="50px" />
</asp:BoundField>
<asp:ButtonField ButtonType="Button" CommandName="SU" Text="SU" >
<ControlStyle Font-Size="7pt"></ControlStyle>
<ItemStyle Width="10px" />
</asp:ButtonField>
<asp:ButtonField ButtonType="Button" CommandName="GIU" Text="GIU" >
<ControlStyle Font-Size="7pt"></ControlStyle>
<ItemStyle Width="10px" />
</asp:ButtonField>
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
Si noti che la griglia è chiusa nell'
UpdatePanelIl codice lato server
Il codice lato server riguarda soltanto, la gestione del salvataggio dei dati della tabella ad ogni operazione di spostamento che eseguiamo tramite i pulsanti di ordinamento. Il codice lato server occorre per eseguire il corretto riordinamento degli items e la renderizzazione a video dei dati riordinati.
In pratica ad ogni spostamento eseguito, Su o Giù, il sistema provvede ad eseguire il calcolo della giusta posizione del singolo Item e ricarica i dati in tabella. Quest'ultima operazione risulta quasi immediata, dal momento che l'
UpdatePanel fa si che ci sia il postback dei dati della sola griglia e non di tutta la pagina, pertanto l'operazione è, compatibilmente, con la velocità della connessione ad Internet, estremamente veloce.
Occorre a questo punto, fare una precisazione circa il termine riordinamento che si sta utilizzando in questo articolo. Il riordinamento dei dati è solo un concetto figurativo, che si esprime e si manifesta solo al momento della renderizzazione a video dei dati. Fisicamente i dati non vengono riordinati, ma ad essi viene solo associato il corretto numero ordinale. Solo in fase di lettura dei dati, ordinati (
ORDER BY) per il campo ordinale, che si esprime e manifesta il concetto di ordinamento dei dati, che appaiono secondo l'ordine definito.
Il codice lato server va impostato dunque nell'evento
RowCommand della griglia.
Ad ogni pressione dei pulsanti SU/GIU, viene scatenato l'evento
RowCommand della
GridView. In esso non dobbiamo far altro che intercettare il tipo di pulsante premuto (tramite la proprietà commandName dl
ButtonField) ed in base ad esso eseguire una semplice rinumerazione del campo ordinale del record/item da spostare e del record successivo o precedente ad esso a seconda del fatto che si è scelto di spostare Su o Giù.
Una volta intercettato il tipo di spostamento, è necessario prelevare:
1) il valore dell'ordinale del record da spostare;
2) l'id del record da spostare;
3) l'id del record precedente se lo spostamento è Su;
4) l'id del record successivo se lo spostamento è Giù.
Una volta prelevati questi dati, occorre solo eseguire una query di update sulla tabella in questione modificando i valori del campo ordinale del record da spostare e del suo precedente o successivo.
Dunque si è capito che l'intervento è su due soli record di dati per volta, quello che si vuole spostare ed il suo precedente o successivo secondo l'ordinamento esistente all'atto dello spostamento.
In particolare, se si tratta di uno spostamento Su:
1) si decrementa di una unità il valore dell'ordinale del record da spostare;
2) si incrementa di una unità il valore dell'ordinale del record precedente;
Se si tratta di uno spostamento Giù:
1) si incrementa di una unità il valore dell'ordinale del record da spostare;
2) si decrementa di una unità il valore dell'ordinale del record successivo;
In sostanza non si fa altro che invertire tra loro i valori degli ordinali dei due record facendo attenzione a prendere il precedente o il successivo a seconda che si vada giù o Su.
Il codice che segue mostra quanto appena detto.
Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles GridView1.RowCommand
Dim idrecordCorrente As Integer = 0
Dim idrecordPrecedente As Integer = 0
Dim idrecordSuccessivo As Integer = 0
Dim ordinale As Integer = 0
Dim indexCorrente As Integer = 0
Dim indexPrecedente As Integer = 0
Dim indexSuccessivo As Integer = 0
Dim strSQL as string = “”
Dim selectedRow As GridViewRow = GridView1.Rows(Convert.ToInt32(e.CommandArgument))
indexCorrente = Convert.ToInt32(e.CommandArgument)
Select Case e.CommandName.ToString
Case "SU"
‘Verifico che non sia la prima riga della griglia, se lo è presento messaggio con alert javaScript
If indexCorrente > 0 Then
‘Prelevo il valore dell'ordinale del record spostato e gli id del record spostato ‘(recordCorrente) e ‘del recordPrecedente
ordinale = CInt(GridView1.Rows(indexCorrente).Cells(1).Text)
idrecordCorrente = CInt(GridView1.Rows(indexCorrente).Cells(0).Text)
idrecordPrecedente = CInt(GridView1.Rows(indexCorrente - 1).Cells(0).Text)
‘Assemblo la stringa sql per eseguire l'update sul record corrente
strSQL = "UPDATE tabella set ordinale=" & ordinale - 1 & " where id = " & idrecordCorrente
‘qui il codice per eseguire l'update del record . . . . . . . . .
‘Assemblo la stringa sql per eseguire l'update sul record Precedente
strSQL = "UPDATE inprimopiano set ordinale=" & ordinale & " where id = " & idrecordPrecedente
‘qui il codice per eseguire l'update del record . . . . . . . . .
‘Qui il codice, per rieseguire la lettura dei dati e ripopolare la griglia dati .. .
Else
‘Gestione del massaggio di errore con alert javaScript del caso in cui si stia tentando di ‘spostare il primo item verso l'alto
Dim x As String = "<script language='JavaScript'> alert('Primo rocord, impossibile andare SU') </script>"
ScriptManager.RegisterStartupScript(Me, Me.GetType(), "x", x, False)
End If
Case "GIU"
‘Verifico che non sia l'ultima riga della griglia, se lo è presento messaggio con alert javaScript
If indexCorrente < GridView1.Rows.Count - 1 Then
‘Prelevo il valore dell'ordinale del record spostato e gli id del record spostato ‘(recordCorrente) e ‘del recordSuccessivo
ordinale = CInt(GridView1.Rows(indexCorrente).Cells(1).Text)
idrecordCorrente = CInt(GridView1.Rows(indexCorrente).Cells(0).Text)
idrecordSuccessivo = CInt(GridView1.Rows(indexCorrente + 1).Cells(0).Text)
‘Assemblo la stringa sql per eseguire l'update sul record corrente
strSQL = "UPDATE inprimopiano set ordinale=" & ordinale + 1 & " where id = " & idrecordCorrente
‘Assemblo la stringa sql per eseguire l'update sul record corrente
strSQL = "UPDATE inprimopiano set ordinale=" & ordinale & " where id = " & idrecordSuccessivo
‘Qui il codice, per rieseguire la lettura dei dati e ripopolare la griglia dati .. .
Else
Dim x As String = "<script language='JavaScript'> alert('Ultimo rocord, impossibile andare GIU') </script>"
ScriptManager.RegisterStartupScript(Me, Me.GetType(), "x", x, False)
End If
End Select
End Sub
L'omissione del codice relativo ai comandi di update, e di lettura dei dati è stata voluta e ritenuta necessaria al fine di rendere più agevole e snella la comprensione del codice e della logica che ad esso sottende.
Conclusioni
Il modulo è stato sviluppato sulla base di una concreta esigenza sorta ad un utilizzatore di un
CMS per la gestione di gallerie di immagini. A tal fine la sua esigenza era quella di poter dare alle immagini presentate sul suo sito web un ordine sequenziale basato sulle sue specifiche esigenze. Nessuno vieta di applicarlo anche in altri scenari per esempio per ordinare un elenco di pagine, oppure la priorità nel caso di un elenco di prodotti su un sito di ecommerce.
Spunti di sviluppo
a) Il sistema potrebbe essere integrato con una funzione
Javascript che provveda essa stessa a spostare lato client, le righe della griglia. Così impostato non sarebbe più necessario il ripopolamento della griglia ad ogni operazione di spostamento. Ad ogni operazione di spostamento corrisponderebbe solo l'azione di update dei record interessati mediante, come già visto, l'incremento/decremento del valore del campo ordinale.
b) Abbiamo visto in questo articolo come implementare funzioni di ordinamento dentro una
GridView tramite
ASP.NET AJAX e
VB.NET. Questo è un metodo ma ce ne sono altri che potrebbero migliorare ulteriormente l'usabilità per l'utente, ad esempio ordinare le righe tramite
Drag & Drop. Un controllo già pronto che ci consente ciò è il
ReoderList contenuto nell'
AJAX Control Toolkit, è possibile vedere una demo funzionate a questo indirizzo (
AJAX Control Toolkit ReorderList Demo ). C'è da notare che qui abbiamo di fronte una list formata da elementi
<li> e non le righe di una
GridView che è composta da
<tr>.
c) Se non vogliamo proprio avere a che fare con il server e quindi con dei roundtrip continui e a volte anche pesanti generati dallo stack
AJAX di
Microsoft possiamo anche optare per soluzioni
jQuery come il plugin
Sortable del pacchetto
jQuery UI di cui potete vedere una demo qui (
jQuery UI Sortable Plugin ). Naturalmente qui dovrete voi farvi carico della serializzazione delle modifiche e quindi sarà necessario costruire
Javascript aggiuntivo che faccia delle chiamate sul server via
HTTP/POST o altro per apportare la modifica nel database.
Ringraziamenti
-
dotNetHell.it per la pubblicazione del presente articolo;
-
David De Giacomi per il supporto nella stesura dell'articolo;
-
Multi Planet 2002 per il continuo stimolo e sostegno nella ricerca di nuove soluzioni da mettere al servizio dei fruitori di Internet;