2009-06-05 6 views
2

Je posté cette semaine dernière aux forums ExtJS, mais personne n'a répondu et je vais un peu fou en essayant de le comprendre:ExtJS - en utilisant une coutume TriggerField comme GridEditor

Je suis assez nouveau à ExtJS (je viens de l'apprendre la semaine dernière pour le travail), mais j'ai travaillé avec d'autres bibliothèques JavaScript depuis un certain temps maintenant. Je fais un contrôle personnalisé pour éditer une liste d'attributs (actuellement peuplés par une requête JSON). J'utilise PropertyGrid avec GridEditor personnalisé (créé en étendant divers champs Ext.form). Tous mes champs personnalisés fonctionnent sauf un, qui est un éditeur de valeur répétée. Fondamentalement le champ va passer un simple tableau de paires clé/valeur 2d par la requête JSON, qu'il affiche dans un EditorGridPanel (à l'intérieur d'un Ext.Window que j'ai créé).

Voici la partie de la demande JSON qui définit l'éditeur de valeur répétitive:

{ 
    key: 'Repeating', 
    type: 'repeating', 
    category: 'Category A', 
    options: { 
     dataArray: [ 
      {key: 'key A', value: 'value A'}, 
      {key: 'key B', value: 'value B'}, 
      {key: 'key C', value: 'value C'} 
     ] 
    } 
} 

La clé est le nom du champ (affiché sur la colonne de gauche du PropertyGrid). Le type indique à la fonction qui crée tous les éditeurs de grille le type d'éditeur personnalisé à utiliser. La catégorie est utilisée pour déterminer à quel PropertyGrid GridEditor est ajouté (j'ai plusieurs PropertyGird, tous contenus dans un Panel avec la disposition: 'acordion'). Les options sont ajoutées au champ Ext.form étendu lors de sa création.

dataArray est attaché à mon éditeur de valeur répétée pour configurer les paires clé/valeur initiales et pour stocker le tableau transmis à GridEditor par la fenêtre Ext.Window utilisée pour l'éditer. Après quelques expériences, j'ai décidé d'utiliser un TriggerField comme GridEditor pour mon type de valeur répétée. Voici le code pour la définition du champ de valeur répétitive:

Ext.form.customFields = { 
    'repeating': Ext.extend(Ext.form.TriggerField, { 
     triggerClass: 'x-form-edit-trigger', 
     enableKeyEvents: true 
    }) 
}; 

Et voici le code qu'il met en place:

Ext.form.customFields['repeating'] = Ext.extend(Ext.form.customFields['repeating'], { 
    onTriggerClick: function() 
    { 
     this.editorWindow.show(); 
    }, 

    listeners: { 
     'render': function(field) 
     { 
      field.editorWindow = new Ext.MultiSelectWindow({ 
       data: field.dataArray, 
       parent: field 
      }); 
     }, 
     'keydown': function(field, event) 
     { 
      event.stopEvent(); 
     }, 
     'beforerender': function() 
     { 
      for (i in this.opt) { 
       if (i != 'store') { 
        this[i] = this.opt[i]; 
       } 
       else { 
        this.store.loadData(this.opt.store); 
       } 
      } 

      if (this.regex != undefined) { 
       this.validator = function(value) 
       { 
        return this.regex.test(value); 
       }; 
      } 
     } 
    } 
}); 

Et enfin, voici le code de la fenêtre de l'éditeur personnalisé:

Ext.MultiSelectWindow = function(args) 
{ 
    var obj = this; 

    obj.args = args; 

    obj.KeyValue = new Ext.data.Record.create([{ 
     name: 'key' 
    }, { 
     name: 'value' 
    }]); 

    obj.gridStore = new Ext.data.Store({ 
     data: obj.args.data, 
     reader: new Ext.data.JsonReader({}, obj.KeyValue), 
     autoLoad: true 
    }); 

    obj.cm = new Ext.grid.ColumnModel([{ 
     id: 'key', 
     header: "Key", 
     dataIndex: 'key', 
     editor: new Ext.form.TextField({ 
      allowBlank: false 
     }), 
     hideable: false, 
     sortable: false, 
     menuDisabled: true, 
     css: 'font-weight: bold;' 
    }, { 
     id: 'value', 
     header: "Value", 
     dataIndex: 'value', 
     editor: new Ext.form.TextField({}), 
     hideable: false, 
     sortable: false, 
     menuDisabled: true 
    }]); 

    obj.gridEditor = new Ext.grid.EditorGridPanel({ 
     cm: obj.cm, 
     height: 280, 
     store: obj.gridStore, 
     autoExpandColumn: 'value', 

     listeners: { 
      'render': function() 
      { 
       // set up local aliases 
       obj.a = new Array(); 
       obj.a.grid = obj.gridEditor; 
       obj.a.store = obj.a.grid.getStore(); 
       obj.a.sel = obj.a.grid.getSelectionModel(); 
      } 
     }, 

     bbar: [{ 
      text: 'Add', 
      cls: 'x-btn-text-icon', 
      icon: '/lib/images/add.png', 

      listeners: { 
       'click': function() 
       { 
        var kv = new obj.KeyValue({ 
         key: '', 
         value: '' 
        }); 

        var row = obj.a.store.data.items.length; 

        obj.a.grid.stopEditing(); 
        obj.a.store.insert(row, kv); 
        obj.a.grid.startEditing(row, 0); 
       } 
      } 
     }, { 
      text: 'Delete', 
      cls: 'x-btn-text-icon', 
      icon: '/lib/images/delete.png', 

      listeners: { 
       'click': function() 
       { 
        if (obj.a.sel.selection) 
         obj.a.store.remove(obj.a.sel.selection.record); 
       } 
      } 
     }] 
    }); 

    obj.panelAll = new Ext.Panel({ 
     border: false, 
     layout: 'absolute', 
     items: [new Ext.Panel({ 
      width: 250, 
      border: false, 
      x: 0, 
      y: 0, 
      items: obj.gridEditor 
     }), new Ext.Panel({ 
      border: false, 
      x: 254, 
      y: 0, 
      items: [new Ext.Button({ 
       cls: 'x-btn-icon-side', 
       icon: '/lib/images/arrow_up.png', 

       listeners: { 
        'click': function() 
        { 

         if (obj.a.sel.selection) { 
          var row = obj.a.sel.selection.cell[0]; 
          var rec = obj.a.store.getAt(row); 

          if (row >= 1) { 
           obj.a.store.remove(rec); 
           obj.a.store.insert(row - 1, rec); 
           obj.a.grid.startEditing(row - 1, 0); 
          } 
         } 
        } 
       } 
      }), new Ext.Button({ 
       cls: 'x-btn-icon-side', 
       icon: '/lib/images/arrow_down.png', 

       listeners: { 
        'click': function() 
        { 
         if (obj.a.sel.selection) { 
          var row = obj.a.sel.selection.cell[0]; 
          var rec = obj.a.store.getAt(row); 
          var len = obj.a.store.data.items.length; 

          if (row < len - 1) { 
           obj.a.store.remove(rec); 
           obj.a.store.insert(row + 1, rec); 
           obj.a.grid.startEditing(row + 1, 0); 
          } 
         } 
        } 
       } 
      })] 
     })] 
    }); 

    obj.win = new Ext.Window({ 
     title: 'Repeating Value Editor', 
     layout: 'fit', 
     closeAction: 'hide', 
     border: false, 
     items: obj.panelAll, 
     width: 300, 
     height: 350, 
     resizable: false, 
     shadow: false, 
     buttonAlign: 'left', 

     buttons: [{ 
      text: 'OK', 
      handler: function() 
      { 
       // reset the repeating field data array 
       obj.args.parent.dataArray = []; 

       for (r in obj.a.store.data.items) 
        obj.args.parent.dataArray[r] = obj.a.store.data.items[r].data; 

       obj.args.parent.setRawValue(attrValueToString(obj.args.parent.dataArray)); 
       obj.win.hide(); 
      } 
     }, { 
      text: 'Cancel', 
      handler: function() 
      { 
       obj.win.hide(); 
      } 
     }] 
    }); 

    obj.show = function() 
    { 
     obj.win.show(); 
     obj.a.store.loadData(obj.args.parent.dataArray); 
    } 
} 

maintenant, pour mon problème: tout cela fonctionne bien, sauf pour la 7e ligne de gestionnaire de bouton « OK » de la fenêtre (obj.args.parent.setRawValue (attrValueToString (obj.args.parent.dataArray));).

obj est un auto-alias. obj.args.parent est un alias pour le champ qui a ouvert la fenêtre de l'éditeur de valeurs répétées. attrValueToString() est une fonction qui prend un tableau 2d et le convertit en chaîne avec une mise en forme spéciale afin de pouvoir l'afficher de façon lisible et significative dans la zone de texte de TriggerField.

Les données sont rechargées dans la variable dataArray du champ et si vous rouvrez l'éditeur, les nouvelles données seront incluses dans la vue. Cependant, je n'arrive pas à obtenir une valeur quelconque à afficher dans TriggerField après sa création. J'ai essayé obj.args.parent.setValue ('abc') et obj.args.parent.setRawValue ('abc'). Aucune exception n'est levée, mais la valeur affichée dans TriggerField ne change pas.J'ai même essayé de créer une fonction personnalisée pour définir la valeur à partir de la TriggerField - quelque chose comme ceci:

Ext.form.customFields['repeating'] = Ext.extend(Ext.form.customFields['repeating'], { 
    setFieldValue: function(value){ 
     this.setValue(value); 
    } 
}); 

Cette fonction personnalisée fonctionne si elle est appelée dans le TriggerField, mais pas lorsqu'il est appelé d'ailleurs (c.-à-de la fenêtre de l'éditeur 'OK' gestionnaire de bouton). La fonction peut être appelée avec succès depuis n'importe où et ne produit aucune exception, mais elle ne définit correctement la valeur que si elle est appelée depuis TriggerField.

Le champ personnalisé fonctionne parfaitement lorsque instancié comme un champ de formulaire de base:

var sample = new Ext.form.customFields['repeating']({ 
    renderTo: Ext.getBody(), 
    dataArray: [ 
     {key: 'key A', value: 'value A'}, 
     {key: 'key B', value: 'value B'}, 
     {key: 'key C', value: 'value C'} 
    ] 
}); 

J'ai épluché la documentation de l'API ExtJS et fait chaque recherche google possible, je peux penser. J'ai trouvé quelques messages du forum qui semblent provenir de personnes ayant un problème similaire, mais ils ne reçoivent jamais de réponse claire.

Toute aide à ce sujet serait très appréciée - merci d'avance!

+0

Donc, vous dites que votre champ personnalisé ne fonctionne pas lorsqu'il est utilisé en tant que GridEditor dans PropertyGrid? Pourriez-vous fournir un exemple complet, qui montre le code défaillant, afin que l'on puisse l'exécuter et le déboguer? Une page de test séparée serait géniale. –

Répondre

1

Je pense que vous devriez utiliser Ext.override pour la fonction onTriggerClick handler au lieu de redéfinir dans votre superclasse.

Vous pouvez le mettre également juste après la création triggerField (peut-être dans le gestionnaire d'événements « rendre ») par attribuer à un nom de fonction, à savoir trigger.onTriggerClick = somefunction.