Developpez.com

Télécharger gratuitement le magazine des développeurs, le bimestriel des développeurs avec une sélection des meilleurs tutoriels

Ext JS 4 : Premiers pas avec MVC
Retours sur les nouveautés du framework JavaScript

Le , par sekaijin, Expert éminent
Bonjour
je viens de faire mes premier pas avec MVC de la version 4.0

mise à part le chargement automatique des classes c'est très proche de l'implémentation MVC que j'avais faite en version 3.x

la différence fondamentale st la séparation du store et du modèle (que j'avais dans le même dossier)

autre élément de divergence je passais par le gestionnaire d'évènement pour pour activer les éléments de mes contrôler. en claire d'associé un évènement à mes actions du contrôleur et les éléments de la vue lançaient des évènements.
Ext-4.0 va un peut plus loin en distinguant ces évènement avec la notion de contrôles. le contrôleur au travers de pattern définit dynamiquement les évènements et les méthodes associées. ces pattern utilise la notation CSS ainsi il n'est plus besoin de définir de handler dans la vue référençant le contrôleur. c'est le contrôleur lui-même qui capte les évènements des objets et leur attache un listener. il conserve donc bien mieux le contrôle.

reste tout comme dans ce que j'avais fait à bien comprendre le cheminement du tout.
pour illuster mon propos je vais reprendre l'exemple fournis dans la doc. "Account Manager"

l'appli est définit dans
Code text : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
+--app 
|   +--controller 
|    |   +--Users.js 
|   +--model 
|    |   +--User.js 
|   +--store 
|    |   +--Users.js 
|   +--view 
|       +--user 
|            +--List.js 
|            +--Edit.js

le modèle définit le type de donnée user (nom, email)
le store est le représentant local de l'espace de stokage.
les vues list et edit affiche une grille pour présenter la liste des users et edit un form pour en éditer un
et le contrôleur orchestre le tout.

voici comment les choses se passent:
à l'ouverture l'affichage de list provoque une lecture dans le store qui n'ayant pas de données en local les demandes au serveur.
de façon asynchrone lorsque les données arrives elle sont placées dans le store en se référent au modèle.
l'arrivée de données dans le modèle provoque la modification de la vue qui affiche les données.

à l'ouverture du formulaire Edit un enregistrement est lu dans le store et référencé par le formulaire.
l'utilisateur le modifie et enregistre.
le contrôleur récupère alors du form la référence de l'enregistrement ainsi que les données.
il remplace les données de l'enregistrement et demande un synchronisation du store.
les modifs sont envoyé au serveur.

dans tout ce processus chacun n'a conscience que de sa partie. c'est un gros avantage mais aussi quand on commence une difficultés. qui assure quelle fonction ?

ExtJs reste très homogène dans son approche. tout comme pour les composant graphiques, les datastores et autres éléments des version précédente c'est le mode descriptif qui est privilégié (face à une approche procédurale).
ainsi tout comme pour le reste on définit un contrôler sous la forme d'un objet de conf listant ses propriétés
Code : Sélectionner tout
1
2
3
4
5
6
Ext.define('AM.controller.Users', { 
    extend: 'Ext.app.Controller', 
    stores: ['Users'], 
    models: ['User'], 
    views: ['user.List','user.Edit'], 
...
il est dommage à mon avis de ne pas avoir été un cran plus loin pour les contrôles comme ceci :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
Ext.define('AM.controller.Users', { 
    extend: 'Ext.app.Controller', 
    stores: ['Users'], 
    models: ['User'], 
    views: ['user.List','user.Edit'], 
    controls:{ 
      'viewport > userlist': {itemdblclick: 'editUser'}, 
      'useredit button[action=save]': {click: 'updateUser'} 
    }, 
...
Mais ExtJS dans ce cas ne le fait pas dans la description mais dans le code de la méthode d'init :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Ext.define('AM.controller.Users', { 
    extend: 'Ext.app.Controller', 
    stores: ['Users'], 
    models: ['User'], 
    views: ['user.List','user.Edit'], 
 
    init: function() { 
        this.control({ 
            'viewport > userlist': { 
                itemdblclick: this.editUser 
            }, 
            'useredit button[action=save]': { 
                click: this.updateUser 
            } 
        }); 
    }, 
...
à part ce détail c'est extrêmement concis le contrôleur se contente de référencer les éléments dont il a besoin et définir les méthodes de traitement des éléments.
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Ext.define('AM.controller.Users', { 
    extend: 'Ext.app.Controller', 
    stores: ['Users'], 
    models: ['User'], 
    views: ['user.List','user.Edit'], 
 
    init: function() { 
        this.control({ 
            'viewport > userlist': { 
                itemdblclick: this.editUser 
            }, 
            'useredit button[action=save]': { 
                click: this.updateUser 
            } 
        }); 
    }, 
 
    editUser: function(grid, record) { 
        var view = Ext.widget('useredit'); 
        view.down('form').loadRecord(record); 
    }, 
 
    updateUser: function(button) { 
        var win    = button.up('window'), 
            form   = win.down('form'), 
            record = form.getRecord(), 
            values = form.getValues(); 
        record.set(values); 
        win.close(); 
        this.getUsersStore().sync(); 
    } 
});
notez la simplicité du code le contrôleur ayant la connaissance de tout le nécessaire. éditer un user c'est ouvrir la vue et charger le formulaire avec le record.
enregistrer c'est récupérer la vue, le record les données mettre les donnée dans le record fermer la vue synchroniser le store.

Un autre point que l'ont peut noter est que même si comme en version 3.x on peut référencer le store dans le composant formulaire on ne le fait pas (j'avais pris la même option)
ainsi le formulaire reste un élément d'affichage qui ne dépends de rien d'autre.
c'est le contrôleur qui assurera la liaison.
on peut tout de même utiliser la référence du store dans le form Ext-4.0 ne l’empêche pas mais alors le contrôler est by-passé. ce qui case le pattern MVC.
j'ai expérimenté avec succès, mais je ne suis pas convaincu de l'approche, l'association dynamique du store et du form. l'idée consiste à définir le form et le store de façon indépendante comme le propose MVC. puis lorsque on ouvre le form associer un store au formulaire. c'est donc bien le contrôleur qui assure la liaison. mais ensuite tout est automatique le contrôleur ne voit plus rien. je pense que même si ça demande un peu de code (très peu) il est préférable d'en rester à la façon de faire proposée dans l'exemple de Sencha.

reste un élément qui permet de démarrer tout ça. là je dois dire que Ext-4.0 fait beaucoup mieux que ce que j'avais fait.
tout comme les contrôleur Ext propose de définir une application. exactement sur le même principe un objet de conf définit les propriétés de l'application et la liste des contrôleurs.
la méthode launch est chargé de définir la vue principale de l'application (un layout plus généralement un container) elle est appelé automatiquement il n'y a rien à faire.

Je n'ai pas encore poussé le bouchon et je n'ai pas par exemple essayé comme je le fais dans mon modèle 3.x avoir un lancement qui tient compte des states de la langue etc.
il faut que je creuse pour cela les requires en effet dans un tel cas on ne peut pas démarrer les vue tant qu'on ne connait pas la langue il y a donc une phase d'init puis de start

A+JYT


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de couetbis couetbis - Membre régulier https://www.developpez.com
le 16/06/2011 à 17:10
Bonjour,
Merci pour cet article.
Lorsque tu auras creusé la question de la gestion des langues, tes conclusions m'intéressent.
Je me suis heurtée à ce point particulier avec l'API SenchaTouch qui utilise ce même principe MVC et je n'ai pas trouvé d'issue
Avatar de Siriru Siriru - Membre du Club https://www.developpez.com
le 23/06/2011 à 11:10
Perso j'ai un souci avec MVC. Comment tu fais pour gérer plusieurs instances du même composant. Un controller est censé pouvoir gérer plusieurs vues j'imagine, or, si je fais un getTabPanel() en prenant en compte ce controller :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Ext.define('Cc.controller.Absences', { 
  extend: 'Ext.app.Controller', 
   
  stores: ['User'], 
 
  models: ['Absence', 'AbsenceHistory'], 
 
  views: ['absence.Panel', 'absence.Grid', 'absence.History', 'absence.Form'], 
   
  refs: [ 
    { ref: 'navigation', selector: 'navigation' }, 
    { ref: 'tabPanel', selector: 'tabpanel' }, 
    { ref: 'absencePanel', selector: 'absencepanel' }, 
    { ref: 'refreshButton', selector: 'absencepanel button[action=refresh]'}, 
    { ref: 'absenceGrid', selector: 'absencegrid' }, 
    { ref: 'absenceHistory', selector: 'absencehistory' }, 
    { ref: 'absenceForm', selector: 'absenceform > form' }, 
    { ref: 'absenceYear', selector: 'absencepanel #absence-year' } 
  ], 
 
....
Si j'ai plusieurs instances d'une vue, c'est impossible d'avoir le "contrôle" sur mes vues de manière indépendante.
Avatar de kenny.kev kenny.kev - Membre éclairé https://www.developpez.com
le 23/06/2011 à 11:23
Tu ne peux pas faire plusieurs instances du meme objet sans faire un cloneConfig().Dedans tu redéfinit l'id et normalement tous devrais fonctionner.
Offres d'emploi IT
Architecte sécurité des systèmes d'information embarqués H/F
Safran - Ile de France - 100 rue de Paris 91300 MASSY
Architecte et intégrateur scade/simulink H/F
Safran - Ile de France - Vélizy-Villacoublay (78140)
Ingénieur analyste programmeur (H/F)
Safran - Auvergne - Montluçon (03100)

Voir plus d'offres Voir la carte des offres IT
Responsable bénévole de la rubrique JavaScript : Xavier Lecomte -