Mots-clé : ExtJs

ExtJs autoLoad et store : howto / comment faire

Si vous ne connaissez pas ExtJs, c’est « à peine » du JavaScript, « à peine » utilisé par IBM, et plein d’autres « petites » entreprises 😉 .

Très puissant mais il manque parfois d’exemple.

En voici un pratique que j’ai eu du mal à mettre en place : pourtant c’est du classique de chez classique.

Je veux ouvrir un onglet qui charge automatiquement des informations de base de données : un onglet dans lequel il y a les informations d’un dossier : nom, prénom, date de naissance, etc.

Assez classique.

Mais disons… que je veux en faire le moins possible. Avec ExtJs, c’est très simple. Enfin simple… après avoir bien cherché !

En fait, l’astuce est qu’il faut appeler la fonction autoLoad, pour que le chargement soit automatique, et avant même d’afficher l’onglet.

Dans mon cas, je voulais afficher Homme ou Femme dans un combo. Donc il fallait avant même d’afficher l’onglet, qu’il précharge le truc dans un magasin de données = store.

Packtlib : Mastering ExtJS : impressions à chaud

Pour les Anglais uniquement, vous serez sûrement intéressées :

Le livre Mastering ExtJS.

Mastering Ext JS montre aux lecteurs comment utiliser le potentiel de Ext JS au complet et créer une application au complet en partant de rien, mais explique aussi comment créer un thème WordPress avec ExtJS. Cette dernière section est assez surprenante, mais semble efficace.

  • Chapter 1. Getting Started
    Les bases pour installer ExtJS (LAMP, ou pour les newbies WAMP etc)
  • Chapter 2. The Login Page
    La plupart des applications ont une page d’identification. L’auteur explique comment faire l’identification « classique » avec ExtJS.
  • Chapter 3. Logout and Multilingual
    La plupart des applications ont une page de déconnexion, et en 2013, il faut savoir rapidement implémenter une autre langue. L’auteur explique comment faire cela : déconnexion et gestion du multilangue.
  • Chapter 4. Advanced Dynamic Menu
    Comment créer des menus dynamiques, qui sont constitués en fonction des droits de la personne connectée (cf chapitres 2 et 3).
  • Chapter 5. User Identification and Security
    Création d’une page de gestion complètes des identifications : comment donner les permissions à des utilisateurs (lister tous les utilisateurs, créer, éditer et supprimer des utilisateurs et aperçu d’une image d’un utilisateur qui va être envoyée).
  • Chapter 6. MySQL Table Management
    Création d’un système modulaire appelé « données statiques ». Liste de toutes les informations d’une table MySQL. Créer de nouveaux enregistrements dans la table. Live search sur les tables. Mettre en place des filtres. Éditer et supprimer des enregistrements. Créer un composant abstrait réutilisable pour toutes les tables.
  • Chapter 7. Content Management
    Gestion de contenu complexe avec ExtJS : comment gérer les associations many-to-many. Comment gérer et faire des formes avec les associations. Explication pour faire des composants réutilisables.
  • Chapter 8. Adding Extra Capabilities
    Possibilités supplémentaires. Comment imprimer des champs d’un panneau de type grille (GridPanel). Comment exporter des champs d’un panneau de type grille (GridPanel) en PDF ou au format Excel. Comment créer des graphiques /courbes. Comment utiliser des composants tiers ou des plugins.
  • Chapter 9. The E-mail Client Module
    Cette partie explique comment développer un client Web mail avec ExtJS. Comment dessiner le client email. Comment lister les emails. Comment créer la boîte de réception (gestion d’un TreePanel). Comment gérer le drag’n’drop entre deux composants (grid et tree). Améliorer le GridPanel de manière impressionnante (customisation).
  • Chapter 10. Preparing for Production
    Comment créer un thème personnaliser. Comment préparer (packager) l’application pour qu’elle soit prête pour la production. Comment utiliser le packager. Il peut sembler y avoir peu de choses dans ce chapitre, mais les explications sont longues et détaillées et j’ai appris énormément de choses.
  • Chapter 11. Building a WordPress Theme
    Je pensais que l’idée était de faire à la main un thème WordPress, mais non : l’idée est d’utiliser tout l’habillage au complet ExtJS, ainsi que le code JavaScript qui va avec, afin de l’intégrer dans une application WordPress. Comment fonctionne WordPress. Comment créer un thème, un header, un footer, une page principale, une Sidebar, une page d’articles et enfin une page de type « Page » (par opposition aux pages de type « Article »)
  • Chapter 12. Debugging and Testing
    C’est un des chapitres les plus pratiques pour la vie quotidienne : la plupart des outils avancés et peu connus y sont, pourtant il sont très utiles : comment déboguer une application ExtJS. Comment tester les applications ExtJS. Les outils utiles (JSLint, YSlow, Sas, Less, YUI Compressor…). Comment passer de ExtJS à une version mobile. Composants tiers et plugins utiles pour développer rapidement. Résumé

Au final, ce livre comporte beaucoup de choses intéressantes, et (à mon sens), même si vous êtes développeur avancé ExtJS, les trois derniers chapitres sont super intéressants et rien que pour ces trois derniers, même si vous trouvez qu’acheter un livre c’est trop cher (ce que je comprends ;)), les quelques 17 € que vous coûteront la version en ligne seront rapidement rentabilisés.

D’ailleurs en parlant de version en ligne, ils ont complètement refait leur reader en ligne, et ce dernier est très bien fait : moi qui suis très critique, je n’ai rien trouvé à redire !

ExtJS : comment envoyer une form au format JSON ?

Je viens de passer 4 heures à chercher comment envoyer, avec ExtJS, une forme au format JSON.

Ce qui suit ne fonctionne pas :

form.submit({
    type: 'ajax',
    headers: {
        'Content-Type': 'application/json'
    },
    url: '/json/destination.php',
    jsonData: data,
    params: {
        mode: 'update'
    },
    success: function(form, action) {
        /* ok !! */
    },
    failure: function(form, action) {
        /* gérer les erreurs */
    }
});

Si vous essayez d’utiliser la fonction « submit » alors vous risquez, comme moi peut être, de ne pas y arriver.
La solution est :

  • récupérer soi même les données via getValues() ;
  • les encoder au format JSON ;
  • les envoyer avec la méthode Ext.Ajax.request().

Voici un exemple de code qui fonctionne :

var data = Ext.JSON.encode({ data: form.getValues(false) }); 
Ext.Ajax.request({
    headers: {
        'Content-Type': 'application/json'
    },
    url: '/json/destination.php',
    method : 'POST',
    jsonData : data,
    params : {
        mode: 'update'
    },
    success: function(form, action) {
        /* ok !! */
    },
    failure: function(form, action) {
        /* gérer les erreurs */
    }   
});

J’ai perdu 4 heures là dessus, alors si je vous en fais gagner 3, n’oubliez pas de me « flattr » 😉

Sencha / ExtJS : comment garder une colonne triée avec une grid ?

Quand on fait une grille de données (datagrid) et qu’on la lie avec un magasin (store) c’est facile.

On peut autoriser à trier par colonnes dans la datagrid.

Seul problème : si le store est un stocké sur le serveur, il fait une seule fois l’appel et ensuite c’est la datagrid qui gère les tris.

Quand on modifie un enregistrement, il est envoyé au serveur, le serveur l’enregistre, et renvoie le résultat de ce qu’il a enregistré. Généralement, il renvoie exactement ce qu’il a reçu. Le seul problème, c’est qu’au retour, la grille ne rafraichit pas l’ordre de tri selon les colonnes qu’on a choisies.

Exemple concret : vous avez une grille avec plein de noms. Vous cliquez sur la colonne « nom », pour la trier par ordre alphabétique. Vous changez le nom « Albert » par « Zoé ». Voici ce qu’il se passe :

  • Le store envoie id=54, nom="Zoé" au serveur ;
  • Le serveur fait la modification en base, et renvoie id=54, nom="Zoé" en retour ;
  • Le store reçoit id=54, nom="Zoé", fait son changement en interne et le transmet à la datagrid ;
  • La datagrid se rafraichit mais ne change pas le tri et laisse "Zoé" à la même place.

La solution : dans le store, lors de l’événement qui signale que le résultat de l’écriture a été intégré (« write« ) il faut forcer l’appel à sort(); qui sera répercuté sur la datagrid automatiquement.

Voici mon code (raccourci à l’extrême sur ma classe de store qui gère les exceptions et plein d’autres choses) :

Ext.define('Ext.data.StoreHandleErrors', {
    extend: 'Ext.data.Store',
    alias: 'data.storehandleerrors',

    constructor: function(config) {
        this.callParent([config]);

        this.on(
            'write',
            function(me, opts) {
                this.sort();
            },
            this
        );
    }
});

ExtJs : dériver un Store « générique » et s’en servir

Ça fait plus d’une journée que je cherche comment faire un Store générique, c’est à dire que j’ai plusieurs Store qui sont tous basés sur le même modèle avec le même type de proxy, etc.

Donc au lieu de faire un copier coller pour chaque Store, j’ai cherché comment en faire un « générique » auquel je pourrai appliquer une configuration « par défaut ».

Voilà le code complet résultat, avec les fonctions qui gère les erreurs possibles renvoyées par Php (session expirée, problème d’écriture en base de données, etc).

Ce qui m’a pris le plus de temps à trouver c’est que pour « surcharger » le constructeur, ça n’est pas la fonction classique « initComponent: function(){ } » mais la fonction de base "constructor: function(config) { }".

Il ne faut, de plus, surtout pas oublier d’appeler le parent, non pas via this.callParent(); mais via this.callParent([config]);.

Ci suit du code, le code de plus d’une journée de travail, en deux parties (j’espère qu’il sauvera du temps à des personnes, ou qu’il les mettra sur la bonne voie !) :

  • première partie = la surcharge
  • seconde partie = exemple d’utilisation de cette surcharge

Première partie : code de la classe

Ext.define('Ext.data.StoreHandleErrors', {
    extend: 'Ext.data.Store',
    alias: 'data.storehandleerrors',

    constructor: function(config) {
        /* (!!) Réécriture par dessus certaines propriétés
         *      du proxy : si jamais elles existent déjà,
         *      elles vont être réécrites.
         */
        config.autoLoad= true;
        config.autoSync= true;
        config.proxy.type= 'ajax';
        config.proxy.reader= {
            type: 'json',
            successProperty: 'success',
            root: 'data',
            messageProperty: 'message'
        };  
        config.proxy.writer= {
            type: 'json',
            writeAllFields: true,
            root: 'data'
        };  
        config.proxy.listeners= {

            exception: function(proxy, response, operation) {

                var error=operation.getError(),
                    title='Erreur du serveur';

                if (error instanceof Array) {
                  error=error.join("
"); } switch(response.status) { case 200: if (response.responseText!='') { var b = Ext.JSON.decode(response.responseText); if (b.title) { title=b.title; } if (b.success==false) { if (b.timeout==true) { windowLoginPanel.show(); } } } break; case -1: var error= 'Le serveur met trop de temps à répondre'+ '

'+ 'On ne peut rien faire, essayez '+ 'd\'actualiser la page.'; break; case 500: var error= 'Le serveur a une erreur interne.'+ '

'+ 'On ne peut rien faire, essayez '+ 'd\'actualiser la page.'; break; default: var error= 'Erreur renvoyée par le serveur non gérée.
'+ 'Détails :
'+ response.statusText+ '

'+ 'On ne peut rien faire, essayez '+ 'd\'actualiser la page.'; break; } Ext.MessageBox.show({ title: title, msg: error, icon: Ext.MessageBox.ERROR, buttons: Ext.Msg.OK }); } }; this.callParent([config]); this.on( 'write', function(proxy, operation) { if ( (operation.action == 'create') || (operation.action == 'update') ) { var m = this.getById( parseInt( operation.resultSet.records[0].internalId ) ); } else if (operation.action == 'destroy') { var m = this.getAt(0); } if (m) { this.panelGridEtEdit.gsGrid.getSelectionModel().select(m); } else { this.panelGridEtEdit.gsGrid.getSelectionModel().deselectAll(); } Ext.example.msg( Ext.String.capitalize(operation.action), operation.resultSet.message ); }, this ); } });

Seconde partie : utilisation de la classe

    var storeAdresses = Ext.create('Ext.data.StoreHandleErrors', {
        model: 'Intranet.Adresse',
        proxy: {
            api: {
                read: '/json/intranet/liste/adresses/',
                create:  '/json/intranet/item/adresse/?mode=create',
                update:  '/json/intranet/item/adresse/?mode=update',
                destroy: '/json/intranet/item/adresse/?mode=destroy'
            }   
        }   
    }); 

ExtJS et grids : double click, comment faire, howto ?

Cela fait une bonne heure que je cherche comment avoir le double click sur une grid générée dynamiquement.

C’est très simple :

Ce code ne fonctionnait pas, donc si vous êtes dans le même cas que moi, n’ayez pas peur :

this.gridAttributs = Ext.create('Ext.grid.Panel', { 
    border: 0,
    store: this.store,
    columns: [ 
        { text: "id", dataIndex: 'id', sortable: true },
        { ... },
        { ... }
    ],
    celldblclick: function(evt, elem, opts ) { 
        console.log('dblclick');
    }
});

Voici le code qui fonctionne :

this.gridAttributs = Ext.create('Ext.grid.Panel', { 
    border: 0,
    store: this.store,
    columns: [ 
        { text: "id", dataIndex: 'id', sortable: true },
        { ... },
        { ... }
    ]
});
this.gridAttributs.on('cellDblClick', function(evt, elem, opts ) {
    console.log('dblclick');
});

J’espère vous avoir évité de perdre l’heure que moi même j’ai perdu ! 😉

ExtJS 4 first look : le livre que j’ai révisé est sorti !

Voilà, on m’a demandé d’être relecteur technique (technical reviewer) du livre « Ext js 4 first look » que vous pouvez trouver ici :

http://www.packtpub.com/ext-js-4-first-look/book

Ce livre parle de ExtJS 4 et de toutes les (nouvelles) possibilités qu’offre le nouveau framework de Sencha, ansi que des comparaisons avec les anciennes versions, pour ceux qui connaissent déjà ExtJS.

Je suis au début :

Livre Ext js 4 first look

C’est un livre très pédagogique, qui vous servira bien si vous débutez.
Vous aurez certainement quelques marque page, notamment en ce qui concerne le MVC, qui n’est pas facile à appréhender (selon moi). J’avais d’ailleurs fait un howto ici.

Mon conseil serait : achetez-le, il est très bien.

Notez cependant qu’il faut un bon niveau JavaScript pour comprendre le livre.

ExtJS : exemple d’un développement

Voici une petite capture d’image d’un Intranet que j’ai développé.

Temps de développement : trois jours à temps plein.

Tout fonctionne parfaitement, en AJAX, synchronisation, etc.

Tout ça pour dire que ExtJS est vraiment une librairie formidable dans ce type de cadre :

Image d'exemple de développement d'un intranet en ExtJS

ExtJs, DataGrid, Store et événements : mémo pour le déboguage

Voici un petit mémo simple : si vous essayez de comprendre dans quel ordre se font les événements, je vous conseille de lire la page ici.

Parmi tout ce qui est expliqué, voici ce que j’utilise le plus souvent : une fonction de trace des événements.
Faites comme moi : un bon copier-coller des familles, et vous aurez dans votre console tous les événements concernant l’objet que vous voulez :

function captureEvents(observable) {
    Ext.util.Observable.capture(
        observable,
        function(eventName) {
            console.info(eventName);
        },
        this
    );		
}
 
Ext.onReady(function(){
    var grid = new Ext.grid.GridPanel({
        ... 
    });
 
    captureEvents(grid);
});

Exemple concret : j’avais un problème, lorsque je créais un nouvel enregistrement dans une DataGrid, j’avais beau essayer de le sélectionner, rien n’y faisait. J’ai cherché pendant des heures, j’ai essayé d’éliminer au fur et à mesure des choses, jusqu’à ce que je mette en place ce code, et là, magie, dans la console :

>beforeload
>datachanged
>load
>read
>add
>datachanged
>beforesync
>write
>datachanged

J’ai vu qu’en fait après l’événement d’ajout « add » sur lequel je comptais pour sélectionner l’élément en cours, il y avait… une mise à jour (« beforesync », « write », « datachanged ») !
En fait ça a fait tilt : j’avais activé la synchronisation automatique des données, et donc juste après l’insertion, le store tentait de se synchroniser, donc la sélection était inévitablement dé-sélectionnée.

Ici aussi, comme dans la plupart de mes articles techniques, j’espère avoir aidé la communauté et avoir évité à d’autre personnes de perdre des heures inutiles, comme celles que j’ai passées !

JavaScript : comment tester, et faire partager très rapidement son code

Supposons que vous vouliez montrer quelques exemples de code JavaScript, mais surtout, le partager rapidement.
C’est très simple : avec http://jsfiddle.net/, vous tapez votre exemple de code, et à la fin vous cliquez sur « sauver » et hop, une URL automatique est créée. Il vous suffit de copier colle le lien pour partager votre code exemple (ou votre code qui démontre qu’une librairie a un problème, par exemple).