Webanwendungen mit DataGrids modernisieren

YUI DataTable mit PHP DataSource
Kommentare

PHP DataSource

Als Backend gehen wir klassischerweise von einer MySQL-Datenbank aus. Die definierte Tabelle repräsentiert die Spalten unseres Grids sowie einen Primary Key id, wie in Listing 3 zu sehen

PHP DataSource

Als Backend gehen wir klassischerweise von einer MySQL-Datenbank aus. Die definierte Tabelle repräsentiert die Spalten unseres Grids sowie einen Primary Key id, wie in Listing 3 zu sehen ist.

Listing 3

CREATE TABLE 'user' (
  'id' int(11) unsigned NOT NULL AUTO_INCREMENT,
  'surname' varchar(255) DEFAULT NULL,
  'firstname' varchar(255) DEFAULT NULL,
  'street' varchar(255) DEFAULT NULL,
  'zip' varchar(10) DEFAULT NULL,
  'city' varchar(50) DEFAULT NULL,
  'country' varchar(50) DEFAULT NULL,
  'email' varchar(255) DEFAULT NULL,
  'color' varchar(255) DEFAULT NULL,
  'amount' float DEFAULT NULL,
  'date' date DEFAULT NULL,
  PRIMARY KEY ('id')
)

Unser SQL basiert auf einem einfachen Select-Statement SELECT * FROM cities. Da wir nur die Datensätze der aktuellen Paginator-Seite auslesen wollen, müssen wir die Get-Variablen start und count berücksichtigen, die wir in der Funktion generateRequest als Query String definiert haben, und diese als LIMIT dem Select-Statement hinzufügen. Auch die Sortierung muss serverseitig implementiert werden, da diese natürlich alle Datensätze und nicht nur die im Grid als aktuelle Seite dargestellten berücksichtigen muss:

$start = isset($_GET['start']) ? (int)$_GET['start'] : 0;
$count = isset($_GET['count']) ? (int)$_GET['count'] : 15;
$sort  = isset($_GET['sort'])  ? $_GET['sort'] : 'rank';
$dir   = ( isset($_GET['dir']) && $_GET['dir'] == 'yui-dt-desc' ) ? 'DESC' : 'ASC';

$sql = sprintf("SELECT * FROM user ORDER BY %s %s LIMIT %d,%d;", $sort, $dir, $start, $count);

Da der Paginator auch die Gesamtzahl der Datensätze benötigt, um die Anzahl der Seiten zu berechnen, ermitteln wir diese in einer zweiten Datenbankabfrage: SELECT COUNT(id) AS count FROM user;. Beide Ergebnisse liefern wir als JSON-Repräsentation im Response des XMLHttpRequest aus: echo json_encode( array(‚results‘ =>

psenv::pushli(); eval($_oclass[„results“]); psenv::popli(); ?>

, ‚totalRecords‘ =>

psenv::pushli(); eval($_oclass[„count“]); psenv::popli(); ?>

) );.

Daten serverseitig Filtern

Für das gezielte Auffinden von Daten in unserem Grid benötigen wir eine Filterfunktion, die es ermöglicht, die Daten einzuschränken. Exemplarisch können die Daten anhand der beiden Spalten „Nachname“ und „Land“ gefiltert werden. Für das Filtern nach Land bietet sich eine Selectbox mit allen vorhandenen Ländern und für den Nachnamen ein Textfeld.

Abb. 5: Exemplarischer DatenfilterAbb. 5: Exemplarischer Datenfilter (Vergrößern)

Um die Filterdaten auch beim Sortieren und im Paginator berücksichtigen zu können, müssen wir die Funktion generateRequest erweitern und die Werte der beiden Formularfelder dem Quer String anhängen:

generateRequest = function(state, table) {
  [...]
  // um Filterfunktion erweitern
  var filter_country = YAHOO.util.Dom.get('filter_country');
  var country = filter_country.options[filter_country.selectedIndex].value;
  var surname = YAHOO.util.Dom.get('filter_surname').value;
  if(country != '')
    query += '&filter[country]=' + country;
  if(surname != '')
    query += '&filter[surname]=' + surname;
  return query;
};

In Listing 4 ist eine einfache Filterfunktion zu sehen, die per generateRequest den Query String abfragt und diesem mittels sendRequest dem DataSource-Objekt übergibt. Des Weiteren erwartet sendRequest ein Callback-Objekt, das die success– und failure-Funktionen definiert, sowie das Objekt, das als Scope für die beiden Funktionen bereitgestellt wird. Das Listing zeigt auch die Event Handler zum Ausführen der Filterfunktion bei Eingabe der Filteroptionen. Das Feld „Land“ wird mit einem einfachen onchange-Event belegt. Für das Feld „Nachname“ wird ein AutoComplete-Widget instanziiert, um nicht nur bei einem onchange-Event, sondern auch beim onkeydown-Event automatisch zu filtern. Da wir die eigentliche AutoComplete-Funktionalität in diesem Fall nicht benötigen, unterdrücken wir diese mit der Zuweisung minQueryLength: 0.

Listing 4

var myFilter = function()  {
  var query = Examples.myConfig.generateRequest(myDataTable.getState(), myDataTable);  myDataSource.sendRequest(query, myDataTable.onDataReturnInitializeTable, myDataTable);
};
  
// Eventhandler "Nachname"
new YAHOO.widget.AutoComplete(
  'filter_surname', 
  'filter_surname_ac',
  new YAHOO.util.FunctionDataSource(myFilter),
  { minQueryLength: 0, queryDelay: 0.5 }
);

// Eventhandler "Land"
YAHOO.util.Event.addListener('filter_country', 'change', myFilter);

// Eventhandler "löschen"
YAHOO.util.Event.addListener('filter_reset', 'click', function(){ YAHOO.util.Dom.get('filter').reset(); myFilter(); });

Das Backend erweitern wir um die Abfrage der neuen Query-Parameter und ergänzen sowohl die Datenbankabfrage zum Ermitteln der Daten als auch die Datenbankabfragen zum Ermitteln der maximalen Anzahl an Datensätzen um eine entsprechende where-clause. Es ist darauf zu achten, dass auch das Select-Statement zur Ermittlung der maximalen Datensätze per where-clause erweitert wird, da der Paginator die korrekte Anzahl an Seiten anhand der gefilterten Daten ermitteln soll.

Inline Cell Editing

Inline Cell Editing ermöglicht die komfortable Manipulation der Daten direkt im Grid. Je Datentyp stellt YUI ein Editor-Widget zur Verfügung, das die Erfassung der Eingabe vereinfacht (Tabelle 2).

Tabelle 2: YUI-2-Editor-Widgets

Widget Beschreibung
YAHOO.widget.DropdownCellEditor Editor mit Selectbox-Element
YAHOO.widget.TextboxCellEditor Editor mit Textfeld-Element
YAHOO.widget.TextareaCellEditor Editor mit Textarea-Element
YAHOO.util.XHRDataSource Editor mit Kalender-Widget
YAHOO.widget.CheckboxCellEditor Editor mit Checkbox-Elementen
YAHOO.widget.RadioCellEditor Editor mit Radiobox-Elementen

Beispielhaft ermöglichen wir das Editieren der Spalten „Stadt“, „Farbe“ und „Datum“ und erweitern die Spaltenkonfiguration um die entsprechenden Editoren. Die manipulierten Daten sollen per XMLHttpRequest in der Datenbank aktualisiert werden. Die Funktion zum Updaten (updateCell) (Listing 5) definieren wir in jeder Editorkonfiguration als asyncSubmitter. Der Funktion werden vom Editor eine Callback-Funktion und der neue Inhalt übergeben. Während der Aktualisierung des Inhalts wird das Grid durch einen Overlay deaktiviert und kann durch Aufruf der Callback-Funktion im success– oder failure-Handler wieder aktiviert werden. Der neue Inhalt wird mit der id des Datensatzes per XMLHttpRequest an das Backend gesendet und in der Datenbank gespeichert. Um die Grid-Zelle mit dem neuen Inhalt zu aktualisieren, wird dieser der Callback-Funktion übergeben. Damit der Cell-Editor beim Klick in eine entsprechend konfigurierte Zelle geöffnet wird, weisen wir dem myDataTable-Objekt einen EventListener zu: myDataTable.subscribe(„cellClickEvent“, myDataTable.onEventShowCellEditor);. Um die Usability zu verbessern, wird die Zelle im Hover-Status farblich markiert, sofern ein Editor für die Zelle definiert ist:

myDataTable.subscribe("cellMouseoverEvent", function(oArgs) {
  if(YAHOO.util.Dom.hasClass(oArgs.target, "yui-dt-editable"))
    this.highlightCell(oArgs.target);
});
myDataTable.subscribe("cellMouseoutEvent",  myDataTable.onEventUnhighlightCell);
Listing 5

var updateCell = function(callback, newValue) {
  var record = this.getRecord(),
        key = column.getKey(),
       id  = record.getData().id;
      
  var value = (key == 'date') ? YAHOO.util.Date.format(newValue, {format:"%Y-%m-%d"}) : newValue;
  var url  = 'grid_update_data.php?id=' + id;
        url += '&' + key + '=' + value;
    
  var request = YAHOO.util.Connect.asyncRequest('GET', url, {
    success: function(o){
      if (o.status == 200 && o.responseText) {
        callback(true, newValue);
      } else {
        alert(o.status + ', ' + o.statusText);
        callback();
      }},
    failure: function(o){ 
      alert(o.status + ', ' + o.statusText);
      callback();
    }
  });
};
Welche Features bringt YUI DataTable sonst noch mit?

  • Row Expansion – Erweiterung von Zeilen um zusätzliche Inhalte
  • Anordnung von Spalten per Drag and Drop
  • Ein- und Ausblenden von Spalten
  • Sortieren von Zeilen per Drag and Drop
  • Skinning Model – komplette Gestaltung des Grids mit individuellen Skins
Fazit

Der Artikel zeigt, dass YUI ein schnelles Erstellen von DataGrids auf Basis unterschiedlicher Datenquellen ermöglicht. Die YUI-2-Komponente DataTable ist, wie alle anderen YUI-2-Komponenten auch, durch das API und viele Beispiele umfassend dokumentiert. Für nahezu jeden Anwendungsfall befinden sich Beispiele auf den YAHOO!-Developer-Seiten. Durch die offene Architektur und die einfache Erweiterbarkeit lassen sich sämtliche Anforderungen an ein DataGrid realisieren. Auch die vielzähligen weiteren Komponenten der YUI Library wie Layout Manager, Menu, TreeView, TabView etc. bieten praxisnahe Lösungsansätze und lassen sich gut zu einem komfortablen User Interface, insbesondere für Webapplikationen, kombinieren.

alt=“Manuel Nickel“ height=“100″ />

Manuel Nickel ist autodidaktischer Entwickler und arbeitet seit mehr als zehn Jahren im Web – seit fast drei Jahren überwiegend in der Entwicklung von Webapplikationen für die lum GmbH in Marburg. Neben der Backend-Entwicklung liegt sein Augenmerk auch stets auf guter Bedienbarkeit und Zugänglichkeit des Frontends. Zu erreichen ist er unter m.nickel[at]lum-software.de.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -