Ext Tree Basics
geschrieben von Micha am 16. Mai 2007 | 23 Kommentare
Heute wollen wir uns das Tree Widget der Ext Library anschauen und die Grundlagen der Erzeugung eines Trees lernen.
Voraussetzungen: Grundkenntnisse in HTML, CSS und Javascript.
Dieses Tutorial basiert auf der Version Ext-1.0, die aktuelle Version kann hier heruntergeladen werden.
Vorbereitungen
Wir benötigen für dieses Tutorial eine leere HTML Datei, die wir basic-tree.html nennen und eine Javascript Datei, basic-tree.js. Legt beide Dateien in einem extra Verzeichnis an.
In die HTML Datei binden wir in der richtigen Reihenfolge die erforderlichen Ext Source Dateien ein und natürlich unser basic-tree.js.
<link rel="stylesheet" type="text/css" href="../ext-1.0/resources/css/ext-all.css" mce_href="../ext-1.0/resources/css/ext-all.css" />
<script type="text/javascript" src="../ext-1.0/adapter/yui/yui-utilities.js" mce_src="../ext-1.0/adapter/yui/yui-utilities.js"></script>
<script type="text/javascript" src="../ext-1.0/adapter/yui/ext-yui-adapter.js" mce_src="../ext-1.0/adapter/yui/ext-yui-adapter.js"></script>
<script type="text/javascript" src="../ext-1.0/ext-all.js" mce_src="../ext-1.0/ext-all.js"></script>
<script type="text/javascript" src="basic-tree.js" mce_src="basic-tree.js"></script>
In die basic-tree.js schreiben wir unsere bekannte Ext.onReady Funktion, die bei korrekter Einbindung der Ext Dateien eine MessageBox aufruft.
Ext.onReady(function(){
Ext.MessageBox.alert('Hallo', 'Ext is now ready for your first tree!');
});
Der Tree braucht natürlich einen Container, in dem er dargestellt werden soll. Dazu erzeugen wir ein Div Element in unserer HTML Datei:
<div id="tree-div" style="width:300px; height:300px; border:2px solid #B2D0F7;"></div>
Wenn soweit alles geklappt hat, löschen wir noch die Ext.MessageBox.alert Zeile und sind bereit für unseren ersten Tree.
Ein statischer Tree
Um erst eimal die Basics zu lernen, wollen wir einen statischen Tree mit ein paar Musikern bauen und uns dann anschauen, wie wir den Tree erweitern können.
Wir müssen zuerst die Ext.BLANK_IMAGE_URL definieren. Das ist die Url zu einen 1×1 transparenten Gif, welches als Platzhalter für die Inline Icons des Trees dient. Der Default Wert ist “http://extjs.com/s.gif”.
Die QuickTips schalten wir auch gleich ein.
Ext.BLANK_IMAGE_URL = "http://localhost/DeinPfadzur/ext-1.0/resources/images/default/s.gif";
Ext.QuickTips.init();
Ok, nun zu unserem Tree. Wir erzeugen eine Instanz der Ext Tree Klasse. Danach brauchen wir ein TreePanel, welches sich in dem tree-div befinden soll. Das TreePanel nutzt den TreeLoader, welcher die Daten für den Tree läd. In unserem Fall sind das statische Daten, es können auch Daten von einer Url geladen werden.
var Tree = Ext.tree;
var myTree = new Tree.TreePanel('tree-div', {
loader: new Tree.TreeLoader(),
containerScroll: true,
animate:true,
rootVisible:true
});
Wir setzen rootVisible auf true, damit wird das oberste Root Node sichtbar. Ihr könnt es auch auf false setzen, je nach Anforderung.
Nun zum eigentlichen Tree:
var Rroot = new Tree.AsyncTreeNode({
text: 'Rockstars',
id:'rockstars',
allowDrag:false,
allowDrop:false,
children: [
{text: 'Pink Floyd', id:'rock-1', children: [
{text: 'David Gilmour', id:'floyd-1', qtip:'Gitarre, Gesang', leaf:true, allowDelete:true},
{text: 'Nick Mason', id:'floyd-2', qtip:'Schlagzeug', leaf:true, allowDelete:true},
{text: 'Richard Wright', id:'floyd-2', qtip:'Keyboards', leaf:true, allowDelete:true}
]},
{text: 'Rolling Stones', id:'rock-2', children: [
{text: 'Mick Jagger', id:'stones-1', leaf:true, allowDelete:true},
{text: 'Keith Richard', id:'stones-2', leaf:true, allowDelete:true},
{text: 'Ron Wood', id:'stones-3', leaf:true, allowDelete:true},
{text: 'Charlie Watts', id:'stones-4', leaf:true, allowDelete:true}
]},
{text: 'Shakira', id:'shakira', leaf:true, allowDelete:true},
{text: 'Madonna', id:'madonna', leaf:true, allowDelete:true},
]
});
myTree.setRootNode(Rroot);
myTree.render();
Wir haben mit Rroot ein Root Node erzeugt und unsere Rockstars einfach als Child Nodes drangehängt. Wenn ein Node weitere Children (Kinder
hat, bekommt es automatisch das Foldericon zugewiesen. Hat ein Node keine Kindelemente mehr, setzt man leaf auf true.
Bei den Musikern von Pink Floyd habe ich zusätzlich qtips definiert, um euch dieses Feature ebenfalls zu zeigen. Fahrt einfach mit der Maus über David Gilmour und es wird “Gitarre, Gesang” als Tooltip angezeigt. Man kann damit wichtige Informationen über das jeweilige Node anzeigen, zB. eine Dateigröße. Mit allowDelete:true erlauben wir das Löschen der Nodes, dazu später.
Euer Tree sollte nun so aussehen:
Wenn ihr möchtet, das alle Tree Nodes sofort aufgeklappt sind, fügt nach myTree.render(); die Zeile
myTree.expandAll();
ein. Drag and Drop haben wir erst einmal nicht erlaubt (allowDrag:false, allowDrop:false), das ist eine andere Baustelle
.
Wir wollen uns nun bei einem Klick auf ein Node die ID anzeigen lassen. Dazu schreiben wir eine kleine Funktion, in der wir uns das SelectionModel holen und schauen, ob ein Node selektiert ist.
myTree.on('click', alertID);
function alertID(node){
if(myTree.getSelectionModel().isSelected(node)){
alert('Die Node-ID ist ' + node.id);
}
};
Oft ist es wichtig zu schauen, ob ein Node das letzte Kind (leaf:true) ist, um zB. nur dafür Drag and Drop zuzulassen. Also passen wir die Funktion noch ein bischen an:
function alertID(node){
if(myTree.getSelectionModel().isSelected(node)){
if (node.isLeaf()){
alert('Die Node-ID ist ' + node.id + ' leaf: true');
} else {
alert('Die Node-ID ist ' + node.id + ' leaf: false');
}
}
};
Jetzt gibts ein bischen mehr Arbeit. Wir wollen dem Tree ein Contextmenü geben, welches bei Rechtsklick auf ein Node verfügbar ist. Das Menü soll uns erlauben, den Tree auf- und zuzuklappen und ein erlaubtes Node zu löschen.
Dazu brauchen wir natürlich ein Menü und 4 Funktionen. Das Menü:
var Menu = new Ext.menu.Menu({
id:'menu',
items: [{
id:'expand',
handler:expandAll,
cls:'expand',
text:'ausklappen'
},{
id:'collapse',
handler:collapseAll,
cls:'collapse',
text:'einklappen'
},'-',{
id:'remove',
handler:removeNode,
cls:'remove',
text: 'löschen'
}]
});
Die Handler sind die Funktionen, die wir nun erstellen werden. Mit cls kann man eigene CSS Klassen erstellen, um dem Menü ein eigenes Aussehen zu geben oder spezielle Icons zu benutzen. Hier die Funktionen:
var sm = myTree.getSelectionModel();
function prepareMenu(node, e){
node.select();
Menu.items.get('remove')[node.attributes.allowDelete ? 'enable' : 'disable']();
Menu.showAt(e.getXY());
}
function collapseAll(){
Menu.hide();
setTimeout(function(){
Rroot.eachChild(function(n){
n.collapse(false, false);
});
}, 10);
}
function expandAll(){
Menu.hide();
setTimeout(function(){
Rroot.eachChild(function(n){
n.expand(false, false);
});
}, 10);
}
function removeNode(){
var n = sm.getSelectedNode();
if(n && n.attributes.allowDelete){
myTree.getSelectionModel().selectPrevious();
n.parentNode.removeChild(n);
}
}
Damit das auch wirklich funktioniert, müssen wir dem Tree mitteilen, was er bei dem contextmenu-Event machen soll:
myTree.on('contextmenu', prepareMenu);
Für unser Context Menü definieren wir zum Schluß noch die CCS Klassen in der HTML Seite:
.expand .x-menu-item-icon {
background-image:url(../PfadZur/ext-1.0/examples/shared/icons/arrow-down.gif);
}
.collapse .x-menu-item-icon {
background-image:url(../PfadZur/ext-1.0/examples/shared/icons/arrow-up.gif);
}
.remove .x-menu-item-icon {
background-image:url(../PfadZur/ext-1.0/examples/shared/icons/fam/delete.gif);
}
Falls jemand nicht richtig mitgekommen ist, hier noch mal der komplette Javascript Code:
Ext.onReady(function(){
Ext.BLANK_IMAGE_URL = "http://localhost/DeinPfadzur/ext-1.0/resources/images/default/s.gif";
Ext.QuickTips.init();
var Tree = Ext.tree;
var myTree = new Tree.TreePanel('tree-div', {
loader: new Tree.TreeLoader(),
containerScroll: true,
animate:true,
rootVisible:true
});
var Rroot = new Tree.AsyncTreeNode({
text: 'Rockstars',
id:'rockstars',
allowDrag:false,
allowDrop:false,
children: [
{text: 'Pink Floyd', id:'rock-1', children: [
{text: 'David Gilmour', id:'floyd-1', qtip:'Gitarre, Gesang', leaf:true, allowDelete:true},
{text: 'Nick Mason', id:'floyd-2', qtip:'Schlagzeug', leaf:true, allowDelete:true},
{text: 'Richard Wright', id:'floyd-2', qtip:'Keyboards', leaf:true, allowDelete:true}
]},
{text: 'Rolling Stones', id:'rock-2', children: [
{text: 'Mick Jagger', id:'stones-1', leaf:true, allowDelete:true},
{text: 'Keith Richard', id:'stones-2', leaf:true, allowDelete:true},
{text: 'Ron Wood', id:'stones-3', leaf:true, allowDelete:true},
{text: 'Charlie Watts', id:'stones-4', leaf:true, allowDelete:true}
]},
{text: 'Shakira', id:'shakira', leaf:true, allowDelete:true},
{text: 'Madonna', id:'madonna', leaf:true, allowDelete:true}
]
});
myTree.setRootNode(Rroot);
myTree.render();
myTree.expandAll();
myTree.on('click', alertID);
myTree.on('contextmenu', prepareMenu);
var sm = myTree.getSelectionModel();
function alertID(node){
if(myTree.getSelectionModel().isSelected(node)){
if (node.isLeaf()){
alert('Die Node-ID ist ' + node.id + ' leaf: true');
} else {
alert('Die Node-ID ist ' + node.id + ' leaf: false');
}
}
};
var Menu = new Ext.menu.Menu({
id:'menu',
items: [{
id:'expand',
handler:expandAll,
cls:'expand',
text:'ausklappen'
},{
id:'collapse',
handler:collapseAll,
cls:'collapse',
text:'einklappen'
},'-',{
id:'remove',
handler:removeNode,
cls:'remove',
text: 'löschen'
}]
});
function prepareMenu(node, e){
node.select();
Menu.items.get('remove')[node.attributes.allowDelete ? 'enable' : 'disable']();
Menu.showAt(e.getXY());
}
function collapseAll(){
Menu.hide();
setTimeout(function(){
Rroot.eachChild(function(n){
n.collapse(false, false);
});
}, 10);
}
function expandAll(){
Menu.hide();
setTimeout(function(){
Rroot.eachChild(function(n){
n.expand(false, false);
});
}, 10);
}
function removeNode(){
var n = sm.getSelectedNode();
if(n && n.attributes.allowDelete){
myTree.getSelectionModel().selectPrevious();
n.parentNode.removeChild(n);
}
}
});
Den fertigen Tree. könnt ihr euch hier anschauen.
- Kategorie: Programmierung, Tutorials
- Tags: ajax, code, ext, framework, html, javascript, tree, tutorial, widgets, yui
- Kommentar-Feed | Trackback URL
- Gelesen: 11644 | Heute: 3
- einen Kommentar schreiben
5 Artikel davor
- Auswertung der beliebtesten WordPress Plugins
- Neuigkeiten von Frank Bueltge
- Endstand Plugin Karneval
- Update auf WordPress 2.2 DE-Edition
- WordPress 2.2 DE Edition released
5 Artikel danach
- WordPress 2.2 erschienen
- Basti in America – Der Arbeitsplatz
- Zwischenstop Pluginkarneval
- Basti in America – das Apartment
- Basti goes America

Eigentlich ziemlich cool, nur ein bisschen schade, dass das ganze in einer JS-Datei abläuft und nicht im Quellcode.
Hallo,
auf einem Testsystem (Linux, Firefox) erscheint bei dem Sample zusätzlich zum Kontextmenü von Ext das normale Browser-Kontextmenü. Ist das ein (bekannter?) Bug in Ext, oder ein Bug von Firefox auf der Plattform? Kann man was machen, damit es funktioniert, also das Browser-Kontextmenü nicht erscheint? Mit Windows/Firefox funktioniert es bei mir.
Nach einem Update (Firefox) trat das Problem auf dem erwähnten Linux-System nicht mehr auf. Hat sich also erledigt.
Konstantin: Ich hatte dieses Problem auch schon einmal, bin mir aber nicht sicher, ob es an der Ext oder am Browser liegt.
habe diese seite über google gefunden und finde das tutorial ganz gut.
zu dem problem mit firefox und dem kontextmenü kann ich euch sagen, dass man das verhalten in den einstellungen von firefox definieren kann. unter “extras”–>”einstellungen…”–>”inhalt” findet man die checkbox “javascript aktivieren”. daneben gibt es den button “erweitert…” und ein klick darauf bringt einen weiteren dialog, der eine checkbox “das kontextmenü deaktivieren oder ersetzen” enhält. einfach diese checkbox anhaken und das firefox kontextmenü erscheint nicht mehr, wenn ein javascript kontextmenü angezeigt wird.
Danke kochi, hab mich schon gewundert, weil es auf einem PC geht und auf dem anderen nicht.
OK, wie man nodes löscht, nodes einfügt oder ändert habe ichh verstanden.
Gibt es eine Methode, den gesamten Bau nach den Änderungen per upload auf den webserver zurückzubringen?
@herman: Natürlich kannst du einen Tree aus einem Backend dynamisch erzeugen und auch Änderungen am Tree im Backend wieder speichern.
OK, gibt es im internet ein kleines Beispiel?
Ich meine auf der Client-Seite, wo ein javacript den inhalt eines trees an den Webserver zurückliefert?
Ich habe gegoogelt, aber leider nichts gefunden.
Ob nun auf er Serverseite php onder python oder.., das könnte sich man dann selbst entsprechend zusammenbauen.
herman, schau dir mal hier unter Examples/Tree den Ext Dependency Tree an. Wenn du dir das Script ansiehst, ganz unten die Funktion save. Ich hoffe, das kommt dem nahe, was du suchst.
Hallo,
sehr schöne Ausführung. Habe lange nach Vergleichbarem gesucht (gegoogelt). Firefox und Opera führen den TreeView einwandfrei aus. Leider funktioniert dieser TreeView nicht auf unserem IE 7, dort meldet er „undefined in 19624“. Kann mir vielleicht jemand sagen, wie man diesen Fehler umgehen kann, da die meisten unserer Kunden den IE benutzten?
Grüße aus Aachen
Mark
Hey Mark, danke für das Kompliment
Hast du dir mal meinen Tree im IE7 angeschaut, bei mir funktioniert er einwandfrei. Falls du eigenen Code probiert hast, achte auf die Kommas im Code. Hast du ein Komma zuviel, der Firefox ignoriert es, der IE führt das komplette Javascript nicht mehr aus. Normalerweise sollte suaberer Ext JS Code im IE7 super laufen, ich hab im Forum auch noch nichts Gegenteiliges gelesen.
Ja, der IE7-Interpreter ist leider sehr genau was die überflüssigen Kommata bei einer literalen Objekterzeugung angeht. Dein Fehler scheint so einer zu sein, schau nach, ob du nach jedem LETZTEN Bezeichner-Wert-Paar in deinen Objekten auch ja keinen Beistrich gemacht hast. Firefox ignoriert das, IE7 leider nicht.
lg, Fabian
Hallo Micha und Fabian,
vielen Dank für Eure schnelle Hilfe. Das mit den Kommata hätte bei mir durchaus sein können, da ich zwischen mehreren Programmiersprachen hin- und herwechsele (u. a. VBA) und schon einiges mit Kommata und Semikola durchgemacht habe. Nein, diesmal waren es nicht diese Zeichen, sondern meine Nachlässigkeit:
Ich habe den „Tree.AsyncTreeNode“ außerhalb der „Ext.onReady“ definiert, das war der Fehler.
Vielen Dank noch mal und liebe Grüße aus Aachen
Mark
hallo,
bei mir funkt. es nicht. kann sein, dass clientseitig nicht funktioniert?
Error:
Zeile: 100
Zeichen: 3600
‘this.root’ is Null oder kein Objekt.
danke
Adrian, mit dieser IE Meldung kann keiner etwas anfangen. Am besten, du nimmst den Firefox und installierst den Firebug. Ohne diese Tools wirst du nicht weit bei der Entwicklung mit Javascript kommen.
Achso, das Tutorial ist für die Ext 1.0 geschrieben.
die ursache ist die version, hatte mit ext 2.0 getestet.
danke für schnelle antwort.
hallo,
ich hatte das gleiche problem wie adrian, bei mir hat es auch nicht funktioniert, weil ich mit der version 2.1 getestet habe.
was muss ich alles abändern damit ich das tutorial auch für die version 2.1 verwenden kann?
gibt es da möglichkeiten ?
im voraus schon mal danke für die rückmeldung.
ema: Du brauchst dir nur die Api-Dokumentation der Ext 2.1 anschauen. Die ist sehr gut. Einige Parameter sind etwas anders als hier in der alten version. Sollte nicht schwer sein, die herauszufinden.
vielen dank für die schnelle antwort,
werd mich gleich mal dran machen.
ich hätte da noch eine frage, ich möchte nur das widget für die trees haben und nicht den ganzen rest verwenden, ich habe auch schon einen ganzen tag versucht alle (wie ich dachte)erforderlichen files rauszuziehen vom ext-2.1 und in ein ordner zu kopieren und die pfade anzupassen. es sind aber so viele pfadangaben in zig ordnern verteilt, so dass immer irgend eine datei zu fehlen scheint und das gegebene beispiel bei mir nicht richtig funktioniert.
es läuft natürlich wenn ich das komplette packet verwende.
meine frage ist, wie machst du es, verwendest du den ganzen ext-*|(2.1) ordner und schreibst drum rum oder lagerst du dir bestimmte files aus in ein extra ordner,von den files die du dazu brauchst?
ich hoffe meine frage war jetzt nicht zu umständlich formuliert.
danke.
Das ist immer abhängig vom Projekt. Du kannst mit Build your own ext deine benötigten files selbst zusammenstellen, so wie du es brauchst. dazu mußt du natürlich wissen, was du brauchst. Der Nachteil ist aberwenn du etwas erweitern willst und das Projekt wächst. Dann fehlen dir andere benötigte Files und du mußt wieder dir eine neue Version bauen. Vorteil der Sache ist natürlich die reduzierte Größe der benötigten Files.
Ich würde es vielleicht so maachen: Entwickeln mit den kompletten Ext Dateien und wenn es fertig ist, kann man ja eine eigene Version für den Onlinebetrieb bauen.
hey micha,
tausend dank für die rückmeldung.
und natürlich auch dafür dass es mal wieder so schnell ging.
die seite für ‘build your own ext’ hilft mir schon sehr viel, vorallem gibt es auch noch ein forum thread dafür.