| Summary: Some usefull examples |
| Author: RapotOR |
| Published: 17/01/2008 |
| Ext Version: v2.0 |
Languages: English Français
|
Contents |
IntroductionJ'ai réalisé une application personnelle. A mes débuts avec ExtJs, pas mal de problèmes sont venu bloquer ma progression et j'ai voulu les rassembler dans ce tutoriel pour aider les personnes qui débutent. Mes recherches dans la doc et les forums a été assez importante. J'espère que la votre sera beaucoup plus petite grâce à ce tutoriel.
Enfin, je voudrais préciser que ma connaissance de ExtJs n'est pas encore parfaite; il y a donc certainement des améliorations possibles au code. Donc, désolé pour d'éventuelles conneries... Je veux juste vous aider :)
Programmation Orientée ObjectJ'avais réalisé ma première version de mon application sans PPO mais c'était une erreur pour une grosse application... Je pense. PPO est beaucoup plus simple d'utilisation. Voici une adresse : http://extjs.com/learn/Manual:Basic_Application_Design
s.gif sur internet?? Non!!!C'est déjà présent dans d'autres tutoriels mais une fois de plus vaut mieux qu'une fois de moins.
Ajoutez cette ligne pour que ExtJs utilise l'image locale:
Ext.BLANK_IMAGE_URL = 'ext/resources/images/default/s.gif'; // 2.0
Selection de la première ligneC'est toujours utile de pouvoir selectionner la première ligne d'un combo ou d'une grid.
Les Combo[[2 Solutions:]]
Votre 'store' est déjà créé et charger dans votre application (orientée object). Effectivement, j'ai personnellement changé mes stores petits et souvent utilisés dans ma classe.
var MyCombo = new Ext.form.ComboBox({ displayField:'field1', store: store1, valueField: 'id', editable: false, typeAhead: true, mode: 'local', triggerAction: 'all', emptyText:'Choose...', selectOnFocus:true, forceSelection : true, anchor:'95%', listeners: { beforerender: function(combo){ MyCombo.setValue(MyCombo.store.getAt(0).data.id); // Ligne finale // MyCombo.setValue(MyCombo.store.collect('id', true)[0]); //pas assez rapide } } });
La ligne finale est la ligne correspondant à la selection de la première ligne. Le champ 'id' correspond au champ 'valueField'.
Deuxième: La deuxième solution envisage le cas ou il faut également créer le store avec le combo.
var MyCombo = new Ext.form.ComboBox({ displayField:'field1', store: new Ext.data.store({ url: 'getdata.php', autoLoad: true, listeners: { load: function(){ MyCombo.setValue(MyCombo.store.getAt(0).data.id); // Ligne finale // MyCombo.setValue(MyCombo.store.collect('id', true)[0]); // pas assez rapide } } reader: new Ext.data.JsonReader({ root: 'data' // le champ 'root' des données; à enlever si nécessaire }, ['id','field1', 'field2']) }), valueField: 'id', editable: false, typeAhead: true, mode: 'local', triggerAction: 'all', emptyText:'Choose...', selectOnFocus:true, forceSelection : true, anchor:'95%' });
Les GridPour les grids, c'est le meme système à part qu'on utilise comme ligne finale celle ci :
MyGrid.getSelectionModel().selectRow(0);
Examples avec ComboAlors ici, c'est une petit code pour montre plusieurs champs dans le combo. On utilise un template : tpl.
var myCombo = new Ext.form.ComboBox({ // use tpl !!! tpl: '<tpl for="."><div class="x-combo-list-item">{id} > {field1}</div></tpl>', valueField: 'id', store: myStore, allowBlank: true, typeAhead: true, mode: 'local', triggerAction: 'all' });
Examples et astuces pour Grid
Différents affichages de colonnesVoici quelques exemples d'affichage de différentes données pour vous donner des idées. Vous pouvez envisage tout et n'importe quoi.
// donc on crée un objet 'ColumnModel' var cmLIST = new Ext.grid.ColumnModel([ { // ajouter un peu de text à la value du champ header: "ID", dataIndex: 'id', sortable: true, renderer: function(v,params,record){ return 'TOTO-'+v; }, width: 30 },{ // On peut meme ajouter de l'HTML header: "Field 1", dataIndex: 'field1', sortable: true, renderer: function(v,params,record){ return '<b>'+v+'</b>'; }, width: 50 },{ // Utiliser un autre champ dans celui en cours; ajouter de la couleur... // par exemple, ici, j'utilise le field3 pour afficher le field2. header: "Field 2", dataIndex: 'field2', sortable: true, renderer: function(v,params,record){ if (record.data.field3 == 1){ // imagine that 'field2' is an other field in store return v+':<font color="#00FF00">'+record.data.field3+'</font>'; }else{ return v+':<font color="#FF0000">'+record.data.field3+'</font>'; } }, width: 50 },{ // afficher une date. :) // perso j'utilise tjs le temps unix... un petit format et hop! header: "Date", dataIndex: 'fielddate', sortable: true, renderer: function(v,params,record){ return Ext.util.Format.date(v,'d-m-Y'); // change the mask if you want.. }, width: 50 },{ // On peut meme ajouter un champ imaginaire calculé à partir d'existants header: "Cost", width: 60, renderer: function(v, params, record){ return (record.data.pricebyunit * record.data.quantity); }, sortable: true } ]); var myGrid= new Ext.grid.GridPanel({ id: 'myGrid', anchor: '100% 100%', store: myStore, // ici un store déjà créé avant. avec les différents champs cm: cmLIST, // et ici on définit l'utilisation de notre ColumnModel ... });
Colonne à partir d'un storeDans la plus part des cas, avec la configuration des bases de données, on utilise des ID pour faire un lien avec une autre table. alors évidement, on récupère des numéros dans certains champs et pas une valeur texte ou autre. Pour ca, la ligne suivante permet la récupération dans un autre store que celui de la grid du texte correspondant à un ID.
... // Dans un champ du ColumnModel renderer: function(v, params, record){ return store2.getAt(stores2.find('id',v)).get('field1'); }, ...
Affichage d'une ligneDans le GridPanel, vous pouvez utiliser la fonction 'getRowClass' dans la propriété 'view' pour changer la css de la ligne.
... view: new Ext.grid.GridView({ getRowClass: function(row, index) { var cls = ''; var data = row.data; // ici un petit test pour changer ou pas la css... changez par le votre! if ( data.field1 < 0 ) { cls = 'row-invalid'; // on assigne le nom d'une classe css! }else{ cls = ''; } return cls; // on retource la valeur... } }), ...
// ici ma classe css qui rendra rouge la ligne si on l'utilise... bien sûr!
.row-invalid {
background-color: red !important;
}
Selectionner une seule ligneLa propriété singleselect... bien sur!
... sm: new Ext.grid.RowSelectionModel({singleSelect:true}), ...
Examples et astuces avec EditorGrid
Colonne DateIci on doit pouvoir afficher la date correctement et en même temps l'éditer !! wow!!
... // dans le ColumnModel { header: "Date", dataIndex: 'datefield', sortable: true, renderer: Ext.util.Format.dateRenderer('d-m-Y'), width: 80, editor: new Ext.form.DateField({ format: 'd-m-Y' }) } ...
Colonne avec combo... // dans le ColumnModel { header: "Suppliers", dataIndex: 'supplierid', sortable: true, width: 80, renderer: function(v, params, record){ // ici on affiche la value à partir du store comme déjà montré dans la section grid return storeSuppliers.getAt(storeSuppliers.find('id',v)).get('name'); }, // et on crée notre combo qui va chercher dans le meme store // ainsi la valeur du champ est tjs l'ID et pas le texte! editor: new Ext.form.ComboBox({ store: storeSuppliers, triggerAction: 'all', emptyText:'', selectOnFocus: true, valueField: 'id', displayField: 'name' }), width: 200 } ...
Editeur dynamiquePeut être que vous devriez avoir besoin de changer l'éditeur en fonction des données. Pour cet exemple, je vais utiliser parfois un textfield ou parfois un combo!
// a store var storeField = new Ext.data.Store({ url: 'getdata.php', reader: new Ext.data.JsonReader({ root: 'enreg' }, ['id','field1', 'field2']) }); // un combo var editorCombo = new Ext.form.ComboBox({ valueField: 'id', displayField: 'field1', store: storeField, allowBlank: true, typeAhead: true, mode: 'local', triggerAction: 'all', emptyText:'Choose...', selectOnFocus: true, forceSelection : true, editable: true }); // ici on crée l'éditeur en fonction du combo var objEditorCombo = new Ext.grid.GridEditor(editorCombo); // un textfield var editorText = new Ext.form.TextField({ allowBlank: false }); // ici on crée l'éditeur en fonction du textfield var objEditorText = new Ext.grid.GridEditor(editorText); var cmLIST = new Ext.grid.ColumnModel([ //... { header: "Field 1", dataIndex: 'field1', sortable: true, width: 400, editor: objEditorCombo // on assigne un des 2 éditeurs. } //.... ]); var myGrid = new Ext.grid.EditorGridPanel({ store: myStore, // ... ici, n'importe quelle propriétés.. cm: cmLIST, // my column model listeners:{ // au moment du double click on va changer l'éditeur celldblclick: function(grid, rowIndex, columnIndex, e){ // mais seulement pour le champ 'field1'... // faudrait pas le changer pour un autre ;) if (grid.getColumnModel().getDataIndex(columnIndex) == "field1"){ // ici un test exemple... à changer par le votre if (grid.store.getAt(rowIndex).get('field2') == 0){ // on assigne dans ce cas le textfield grid.getColumnModel().setEditor(columnIndex,objEditorText); }else{ // et dans l'autre le combo grid.getColumnModel().setEditor(columnIndex,objEditorCombo); } } }, afteredit: function(e){ // après l'édition, dans le cas ou l'éditeur était le combo, // il se pourrait qu'il faille changer en même temps d'autres colonnes // qui sont liées. if (e.field == 'field1' && e.record.get('field2') == 0){ e.record.set('field2',storeField.getAt(storeField.find('id',e.value)).get('field2')); } } } });
Eviter des pertes de mémoireIl y a pas mal de topics qui parlent de pertes de mémoires. Qu'est ce que c'est? Avec l'utilisation de certains composants, certaines DIV ne sont pas détruites avec l'utilisation de l'application et la mémoire augmente sans cesse... J'ai remarqué cela avec msg, modal windows, grid pour l'instant. Vous vérifier cela, utilisez l'extension FIREBUG sous FIREFOX.
Ext.msgCe n'est en fait pas vraiment un problème. A chaque fois qu'une fenêtre apparaît, les 'shadow' (masque, ombres sous les fenêtres etc...) DIV ne sont pas créées à chaque fois; elles sont réutilisées à nouveau à chaque fenêtre ('show'). Donc ce n'est pas nécessaire de les supprimer.
Modal windowArgh! Pas très bon! C'est la fenêtre avec l'option d'un masque qui cache l'application en arrière. J'ai créé une petite extend de Ext.Window avec un listener qui supprimer les mask, shadow correspondants
Ext.ModalWindow = Ext.extend(Ext.Window, { initComponent : function(){ Ext.Window.superclass.initComponent.call(this); }, modal: true, closable: true, modal: true, shadow: false, minimizable: false, draggable: false, resizable: false, width: 500, height: 'auto', layout: 'anchor', plain: true, listeners: { beforedestroy: function(w){ if (w.mask){Ext.destroy(w.mask);} if (w.proxy){Ext.destroy(w.proxy);} if (w.plain){Ext.destroy(w.plain);} } } }); // et son utilisation : var modalWin = new Ext.ModalWindow({ id: 'modalWin', title: 'Intranet Logon.', width: 360, buttons: [ { text: 'Quit', handler: function(){ modalWin.destroy(); } }] }); modalWin.show();
Vider un panelDans ce cas, j'avais quelques grids dans un panel et certaines DIV n'était pas supprimées. Du coup, à chaque fois, j'avais des DIV qui s'amoncelait... et la mémoire qui augmentait...
<div id="ext-gen728" class="x-dd-drag-proxy x-dd-drop-nodrop x-grid3-col-dd" style="position: absolute; z-index: 15000; visibility: hidden; left: -10000px; top: -10000px;"> <div class="x-dd-drop-icon"/> <div id="ext-gen730" class="x-dd-drag-ghost"/> </div> <div id="ext-gen733" class="col-move-top"/> <div id="ext-gen734" class="col-move-bottom"/>
La meilleure solution pour moi était :
myPanel.items.each(function(item, index, len){ item.purgeListeners(); myPanel.remove(item,true); // le 'true' , cest pour l'option destroy. // à noter que le '.destroy', ca marchait pas des masses pour éviter les DIV restantes. });
Form avec gridComme pas mal de personnes sur le forum, j'ai voulu mettre une grid dans un formpanel... mais evidement, ce ne fut pas si facile au moment du submit ... :D Ici, c'est ma méthode. Peut être il y en a d'autres. ( Une extend du formpanel avec grid serait peut être mieux... )
Changement des donnéesExt.Ajax.request({ url: 'getdata.php?type=da&idv='+PR_ID, callback: function(options,success,response){ var myResponse = Ext.util.JSON.decode(response.responseText); myForm.form.setValues(myResponse); // mettre les données dans la grid à partir du champ grid1 var myGrid = Ext.getCmp('myGrid'); myGrid.store.loadData(myResponse.grid1); } });
Savegarde des donnéesvar myForm = new Ext.form.FormPanel({ ... items: [ { xtype: 'textfield', name: 'field1', fieldLabel: 'Field 1' },{ xtype: 'textfield', name: 'field2', fieldLabel: 'Field 2' },{ xtype: 'grid', // ... d'autres propriétés ici } ] bbar: [ { xtype: 'button', // c'est le même que d'utiliser "new Ext.Button()" (voir doc) text: 'Save' , iconCls: 'save', handler : function() { var storeValue=[]; var myGrid = Ext.getCmp('myGrid'); var allRecords = myGrid.store.getRange(0); // je mets les données dans une variable storeValue for (i=0;i < allRecords.length;i++) { storeValue[i] = allRecords[i].data; } // je récup les données de la form var dataForm = generalInfos.getForm().getValues(); // j'envoi la requete ajax avec les données complètes. Ext.Ajax.request({ url: 'submitdata.php', // je paramètre la requête params: { param1: 'toto', param2: 'titi', field1: dataForm.field1, field2: dataForm.field2, grid1: Ext.encode(storeValue) // Données de la grid au format JSON... }, callback: function(options,success,response){ alert('SUBMIT!'); } }); } } ...