moleskine di un programmatore

Appunti di viaggio tra bit e byte
jQuery Flexigrid Fluent Interface

Dopo aver introdotto il plugin Flexigrid per jQuery in un progetto Asp.Net MVC per convertire una tabella html statica in una griglia interattiva creiamo una interfaccia fluente in c# per la creazione di una tabella partendo da zero.

Come indicato nella documentazione (esempio 3) è possibile definire nel dettaglio la struttura della griglia e le features abilitate (pulsanti, ordinamento, ricerca, paginazione)

   1: $("#flex1").flexigrid
   2:             (
   3:             {
   4:             url: 'post2.php',
   5:             dataType: 'json',
   6:             colModel : [
   7:                 {display: 'ISO', name : 'iso', width : 40, sortable : true, align: 'center'},
   8:                 {display: 'Name', name : 'name', width : 180, sortable : true, align: 'left'},
   9:                 {display: 'Printable Name', name : 'printable_name', width : 120, sortable : true, align: 'left'},
  10:                 {display: 'ISO3', name : 'iso3', width : 130, sortable : true, align: 'left', hide: true},
  11:                 {display: 'Number Code', name : 'numcode', width : 80, sortable : true, align: 'right'}
  12:                 ],
  13:             buttons : [
  14:                 {name: 'Add', bclass: 'add', onpress : test},
  15:                 {name: 'Delete', bclass: 'delete', onpress : test},
  16:                 {separator: true}
  17:                 ],
  18:             searchitems : [
  19:                 {display: 'ISO', name : 'iso'},
  20:                 {display: 'Name', name : 'name', isdefault: true}
  21:                 ],
  22:             sortname: "iso",
  23:             sortorder: "asc",
  24:             usepager: true,
  25:             title: 'Countries',
  26:             useRp: true,
  27:             rp: 15,
  28:             showTableToggleBtn: true,
  29:             width: 700,
  30:             height: 200
  31:             }
  32:             );   

Sfruttando il serializzatore JSON di .Net è facile creare una classe builder che ci permetta di creare una griglia da zero usando c#, intellisense e tutti i vantaggi che ne derivano.

Inseriamo quindi nella nostra cartella models (per convenienza) una nuova classe che mima la struttura ammessa dal costrutto javascript. Da notare l'esatta corrispondenza dei nomi, necessaria  per avere una rappresentazione fedele in JSON della nostra griglia.

   1: using System.Collections.Generic;
   2: using System.Web.Script.Serialization;
   3:  
   4: namespace FlexiGridTutorial.Models
   5: {
   6:     public class FlexiGridBuilder
   7:     {
   8:         public enum Align
   9:         {
  10:             left,
  11:             center,
  12:             right
  13:         } ;
  14:  
  15:         public class Column
  16:         {
  17:             public readonly string display;
  18:             public readonly string name;
  19:             public readonly string width;
  20:             public readonly bool sortable;
  21:             public readonly Align align;
  22:             public readonly bool hide;
  23:  
  24:             public Column(string display, string name, string width, bool sortable, Align align, bool hide)
  25:             {
  26:                 this.display = display;
  27:                 this.name = name;
  28:                 this.width = width;
  29:                 this.sortable = sortable;
  30:                 this.align = align;
  31:                 this.hide = hide;
  32:             }
  33:         } ;
  34:  
  35:         public class Button
  36:         {
  37:             
  38:         }
  39:  
  40:         public class SearchItem
  41:         {
  42:             public string display;
  43:             public string name;
  44:             public bool isdefault;
  45:  
  46:             public SearchItem(string display, string name, bool isdefault)
  47:             {
  48:                 this.display = display;
  49:                 this.name = name;
  50:                 this.isdefault = isdefault;
  51:             }
  52:         }
  53:         
  54:         public string url;
  55:         public string dataType;
  56:         public IList<Column> colModel;
  57:         public IList<Button> buttons;
  58:         public IList<SearchItem> searchitems;
  59:         public string sortname;
  60:         public string sortorder;
  61:         public bool usepager;
  62:         public string title;
  63:         public bool useRp;
  64:         public short rp;
  65:         public bool showTableToggleBtn;
  66:         public short width;
  67:         public short height;
  68:  
  69:         public FlexiGridBuilder(string param_title)
  70:         {
  71:             this.title = param_title;
  72:             this.url = null;
  73:             this.dataType = "json";
  74:             
  75:             this.usepager = true;
  76:             this.useRp = true;
  77:             this.rp = 15;
  78:             this.showTableToggleBtn = true;
  79:             this.width = 500;
  80:             this.height= 200;
  81:             this.sortorder = "asc";
  82:             
  83:             this.colModel = new List<Column>();
  84:             this.buttons = new List<Button>();
  85:             this.searchitems = new List<SearchItem>();
  86:         }
  87:  
  88:         public FlexiGridBuilder SetDataUrl(string u)
  89:         {
  90:             this.url = u;
  91:             return this;
  92:         }
  93:         
  94:         public FlexiGridBuilder SetWidth(short w)
  95:         {
  96:             this.width = w;
  97:             return this;
  98:         }
  99:  
 100:         public FlexiGridBuilder SetHeight(short h)
 101:         {
 102:             this.height= h;
 103:             return this;
 104:         }
 105:         
 106:         public FlexiGridBuilder ShowToggleButton(bool bSet)
 107:         {
 108:             this.showTableToggleBtn = bSet;
 109:             return this;
 110:         }
 111:  
 112:         public FlexiGridBuilder UsePager(bool bSet)
 113:         {
 114:             this.usepager = bSet;
 115:             return this;
 116:         }
 117:         
 118:         public FlexiGridBuilder SetDefaultSort(string field, string order)
 119:         {
 120:             this.sortname = field;
 121:             this.sortorder = order;
 122:             return this;
 123:         }
 124:  
 125:         public FlexiGridBuilder AddColumn(string col_display, string col_name, short col_width, bool col_sortable, Align col_align, bool col_hide)
 126:         {
 127:             return AddColumn(col_display, col_name, col_width.ToString(), col_sortable, col_align, col_hide);
 128:         }
 129:  
 130:         public FlexiGridBuilder AddColumn(string col_display, string col_name, string col_width, bool col_sortable, Align col_align, bool col_hide)
 131:         {
 132:             colModel.Add(new Column(col_display, col_name, col_width, col_sortable, col_align, col_hide));
 133:             if (this.sortname == null)
 134:                 this.sortname = col_name;
 135:  
 136:             return this;
 137:         }
 138:  
 139:         public FlexiGridBuilder AddColumn(string col_display, string col_name, string col_width, bool col_sortable, Align col_align)
 140:         {
 141:             return AddColumn(col_display, col_name, col_width, col_sortable, col_align, false);
 142:         }
 143:  
 144:         public FlexiGridBuilder AddColumn(string col_display, string col_name, short col_width, bool col_sortable, Align col_align)
 145:         {
 146:             return AddColumn(col_display, col_name, col_width.ToString(), col_sortable, col_align, false);
 147:         }
 148:         
 149:         public FlexiGridBuilder AddSearchItem(string si_display, string si_name, bool si_isdefault)
 150:         {
 151:             searchitems.Add(new SearchItem(si_display, si_name, si_isdefault));
 152:             return this;
 153:         }
 154:  
 155:         public string ToJson()
 156:         {
 157:             var serializer = new JavaScriptSerializer();
 158:             return serializer.Serialize(this);
 159:         }
 160:  
 161:         public string Create(string id)
 162:         {
 163:             return string.Format("$(\"#{0}\").flexigrid({1});", id, ToJson());
 164:         }
 165:     }
 166: }
 167:  

Ora grazie agli extension methods andiamo a creare due helpers per la generazione della griglia estendendo la classe HtmlHelper

   1: using System.Web.Mvc;
   2:  
   3: namespace FlexiGridTutorial.Models
   4: {
   5:     public static class FlexiGridHtmlHelper
   6:     {
   7:         public static string FlexiGridPlaceholder(this HtmlHelper htmlHelper, string id)
   8:         {
   9:             return string.Format("<table id=\"{0}\" style=\"display: none\"></table>", id);
  10:         }
  11:  
  12:         public static FlexiGridBuilder NewFlexiGrid(this HtmlHelper htmlHelper, string title)
  13:         {
  14:             return new FlexiGridBuilder(title);
  15:         }
  16:     }
  17: }

Realizzate le classi di supporto è velocissimo creare una griglia enhanced direttamente nella nostra view. Prima di tutto creiamo la solita Action chiamata Tutorial3 e la relativa view.

Definiamo la nostra tabella nel codice html usando il nuovo helper FlexiGridPlaceholder

   1: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
   2:     <%=Html.FlexiGridPlaceholder("tablefx") %>
   3: </asp:Content>

Passiamo poi alla definizione vera e propria della struttura della tabella tramite la nostra interfaccia fluente

   1: Html.NewFlexiGrid("Contacts")
   2:     .AddColumn("Name", "Name", 200, true, FlexiGridBuilder.Align.left)
   3:     .AddColumn("Address", "Address", 180, true, FlexiGridBuilder.Align.left)
   4:     .AddColumn("Phone", "Phone", 120, true, FlexiGridBuilder.Align.left)
   5:     .AddSearchItem("Name", "Name", true)
   6:     .AddSearchItem("Address", "Address", false)
   7:     .AddSearchItem("Phone", "Phone", false)
   8:     .Create("tablefx")

Wrappiamo la chiamata al nostro helper nell'evento "document ready" di jQuery in modo da costruire la griglia al momento opportuno.

Ecco il sorgente completo di Tutorial3.aspx

   1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true"
   2:     CodeBehind="Tutorial3.aspx.cs" Inherits="FlexiGridTutorial.Views.Home.Tutorial3" %>
   3:  
   4: <%@ Import Namespace="FlexiGridTutorial.Models" %>
   5: <asp:Content ID="Content1" ContentPlaceHolderID="headerPlaceHolder" runat="server">
   6:     <script type="text/javascript">
   7:         $(function() {
   8:         <%= Html.NewFlexiGrid("Contacts")
   9:             .AddColumn("Name", "Name", 200, true, FlexiGridBuilder.Align.left)
  10:             .AddColumn("Address", "Address", 180, true, FlexiGridBuilder.Align.left)
  11:             .AddColumn("Phone", "Phone", 120, true, FlexiGridBuilder.Align.left)
  12:             .AddSearchItem("Name", "Name", true)
  13:             .AddSearchItem("Address", "Address", false)
  14:             .AddSearchItem("Phone", "Phone", false)
  15:             .Create("tablefx")%>
  16:         });
  17:     </script>
  18:  
  19: </asp:Content>
  20: <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  21:     <%=Html.FlexiGridPlaceholder("tablefx") %>
  22: </asp:Content>

Ed ecco il risultato:

image

Per quanto incompleta (non copre tutte opzioni) la nostra interfaccia fluente ci permette agevolmente di creare agevolmente una griglia completa nascondendo completamente l'implementazione JSON e mettendo a disposizione l'intellisense.

Nel prossimo post implementeremo la comunicazione asincrona dei dati con il server.

Buon we.

Download: FlexiGridTutorial02.zip (218KB)

Utilizzo di Flexigrid in ASP.NET MVC

Flexigrid è un plugin di jQuery che permette di aggiungere notevoli funzionalità ed un look & feel avanzato alle nostre tabelle HTML.

Indipendentemente dalle funzionalità lato client la bellezza del plugin sta (secondo me) nella semplicità nel popolare la griglia tramite chiamate JSON asincrone.

Supponiamo di voler creare una semplice rubrica, la prima cosa da fare è definire il nostro modello di dati.

Ecco la definizione della classe ContactModel

   1: namespace FlexiGridTutorial.Models
   2: {
   3:     public class ContactModel
   4:     {
   5:         public string Name { get; set; }
   6:         public string Address { get; set; }
   7:         public string Phone { get; set; }
   8:         
   9:         public ContactModel()
  10:         {
  11:         }
  12:  
  13:         public ContactModel(string name, string address)
  14:         {
  15:             Name = name;
  16:             Address = address;
  17:         }
  18:  
  19:         public ContactModel(string name, string address, string phone)
  20:         {
  21:             Name = name;
  22:             Address = address;
  23:             Phone = phone;
  24:         }
  25:     }
  26: }

 

Aggiungiamo quindi la definizione del modello della nostra rubrica: ContactsListModel

   1: using System.Collections.Generic;
   2:  
   3: namespace FlexiGridTutorial.Models
   4: {
   5:     public class ContactsListModel
   6:     {
   7:         public IEnumerable<ContactModel> Contacts { get; private set; }
   8:         public string ID { get; private set; }
   9:         public ContactsListModel(string listID, IEnumerable<ContactModel> contacts)
  10:         {
  11:             ID = listID;
  12:             Contacts = contacts;
  13:         }
  14:     }
  15: }

Per semplificare il progetto creiamo una classe helper che fornirà i dati necessari al popolamento della rubrica.

   1: using System.Collections.Generic;
   2: using FlexiGridTutorial.Models;
   3:  
   4: namespace FlexiGridTutorial.Helpers
   5: {
   6:     public static class SampleData
   7:     {
   8:         public static IList<ContactModel>    Contacts
   9:         {
  10:             get
  11:             {
  12:                 var result = new List<ContactModel>();
  13:  
  14:                 result.Add(new ContactModel("Mario Rossi", "Via Garibaldi, 9 - Milano", "555-0000"));
  15:                 result.Add(new ContactModel("Giovanni Verdi", "Via Fantasia, 10 - Roma", "555-1111"));
  16:                 result.Add(new ContactModel("Roberto Bianchi", "Piazza dei Partigiani, 20 - Roma", "555-2222"));
  17:                 return result;
  18:             }
  19:         }
  20:     }
  21: }

Aggiungiamo ora il primo step del tutorial modificando la classe HomeController inserendo la action per il primo step

   1: public ActionResult Tutorial1()
   2: {
   3:     return View(SampleData.Contacts);
   4: }

Passiamo alla creazione della relativa view tramite la scorciatoia introdotta in Beta 1, posizionare il caret nello scope di Tutorial1 e premere Ctrl+M, Ctrl+V (Marry View)

image

In questo modo la view creata è tipizzata per gestire l'enumerazione di ContactModel.
Per semplicità creiamo una partial view che renderizza l'elenco dei contatti in una tabella html.

Aggiungiamo un nuovo usercontrol ContactsList.ascx nella cartella Views\Home

Sorgente di ContactsList.ascx

   1: <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ContactsList.ascx.cs" Inherits="FlexiGridTutorial.Views.Home.ContactsList" %>
   2:     <table id="<%=ViewData.Model.ID%>">
   3:         <thead>
   4:             <tr>
   5:                 <th class="name">
   6:                     Name
   7:                 </th>
   8:                 <th class="address">
   9:                     Address
  10:                 </th>
  11:                 <th class="phone">
  12:                     Phone
  13:                 </th>
  14:             </tr>
  15:         </thead>
  16:         <tbody>
  17:         
  18:         <%foreach (var contact in ViewData.Model.Contacts)
  19:           {%>
  20:             <tr>
  21:                 <td class="name">
  22:                     <%=contact.Name %>
  23:                 </td>
  24:                 <td class="address">
  25:                     <%=contact.Address%>
  26:                 </td>
  27:                 <td class="phone">
  28:                     <%=contact.Phone%>
  29:                 </td>
  30:             </tr>
  31:             <%} %>
  32:         </tbody>
  33:     </table>

Sorgente di ContactsList.ascx.cs

   1: namespace FlexiGridTutorial.Views.Home
   2: {
   3:     public partial class ContactsList : System.Web.Mvc.ViewUserControl<FlexiGridTutorial.Models.ContactsListModel>
   4:     {
   5:     }
   6: }

In questo caso il nostro controllo è tipizzato per la classe ContactsListModel in modo da poter associare un id alla lista di contatti.

Aggiungiamo gli stili necessari nel site.css per definire la larghezza delle colonne (necessario per una corretta visualizzazione della griglia).

   1: th.name
   2: {
   3:     width:200px;    
   4: }
   5:  
   6: th.address
   7: {
   8:     width:300px;    
   9: }
  10:  
  11: th.phone
  12: {
  13:     width:100px;    
  14: }
  15:  
  16: td.name
  17: {
  18:     width:<