2012-03-27 11 views
3

Lassen Sie uns sagen, ich habe ein Modell namens VehicleExtJs und verschachtelte Modelle

Ext.define('AM.model.Vehicle', { 
    extend: 'Ext.data.Model', 
    fields: [ 
     {name: 'brandId', type: 'int'}, 
     {name: 'brandName', type: 'string'}, 
     {name: 'modelId', type: 'int'}, 
     {name: 'modelName', type: 'string'}, 
     {name: 'yearOfRelease', type: 'int'} 
    ] 

}); 

Wie Sie sehen können, das Fahrzeugmodell hat Felder „brandid“, „Marke“ usw. Zum Beispiel möchte ich bearbeiten eine Instanz dieses Modells. Ich erstelle ein Bearbeitungsformular, das eine Combobox mit dem Feld 'brandId' verknüpft hat. Dann speichere ich die Formularwerte an eine Modellinstanz mit diesem

values = form.getValues(); 
record.set(values); 

Das alles funktioniert gut, aber es gibt ein Problem mit allen Feldern, die einige äußere Modelle darstellen: nur ids aktualisiert werden, während alle anderen Felder , die von id abhängen, bleiben gleich.

In einer normalen OOP-Sprache (Java zum Beispiel), würde ich eine Klasse CarBrand erstellen und eine Instanz dieser Klasse in der Vehicle-Klasse platzieren. In ExtJs 4 haben sie hasMany Beziehung, aber nicht hasOne.

Was ist der beste Ansatz in ExtJS 4 für solche verschachtelten Modelle?

Antwort

10

4,0 * nicht die hasOne Beziehung unterstützt. 4.1 soll es unterstützen.

für 4.0.7 Ich habe die folgende Überschreibung an Ort und Stelle.

Ext.define('HOD.overrides.Form', {}, function() { 

/* 
* Implementing a nested setValues for forms with 
* arrays in them. 
*/ 
Ext.override(Ext.form.Basic, { 
    setValues: function(values, arrayField) { 
     var me = this; 

     function setVal(fieldId, val) { 
      if (arrayField) { 
       fieldId = arrayField + '.' + fieldId; 
      } 
      var field = me.findField(fieldId); 
      if (field) { 
       field.setValue(val); 
       if (me.trackResetOnLoad) { 
        field.resetOriginalValue(); 
       } 
      } else if(Ext.isObject(val)) { 
       me.setValues(val, fieldId); 
      } 
     } 

     if (Ext.isArray(values)) { 
      // array of objects 
      Ext.each(values, function(val) { 
       setVal(val.id, val.value); 
      }); 
     } else { 
      // object hash 
      Ext.iterate(values, setVal); 
     } 
     return this; 
    }, 
    /** 
    * Persists the values in this form into the passed {@link Ext.data.Model} object in a beginEdit/endEdit block. 
    * @param {Ext.data.Model} record The record to edit 
    * @return {Ext.form.Basic} this 
    */ 
    updateRecord: function(record) { 
     var values = this.getFieldValues(), 
     name, 
     obj = {}; 

     function populateObj(record, values) { 
      var obj = {}, 
      name; 

      record.fields.each(function(field) { 
       name = field.name; 
       if (field.model) { 
        var nestedValues = {}; 
        var hasValues = false; 
        for(var v in values) { 
         if (v.indexOf('.') > 0) { 
          var parent = v.substr(0, v.indexOf('.')); 
          if (parent == field.name) { 
           var key = v.substr(v.indexOf('.') + 1); 
           nestedValues[key] = values[v]; 
           hasValues = true; 
          } 
         } 
        } 
        if (hasValues) { 
         obj[name] = populateObj(Ext.create(field.model), nestedValues); 
        } 
       } else if (name in values) { 
        obj[name] = values[name]; 
       } 
      }); 
      return obj; 
     } 

     obj = populateObj(record, values); 

     record.beginEdit(); 
     record.set(obj); 
     record.endEdit(); 

     return this; 
    } 
}); 

Was ich tun kann, ist in meinen Formen Ich erstelle sie mit Namen wie so.

// Contact details 
{ 
    xtype: 'fieldcontainer', 
    defaultType: 'textfield', 
    layout: 'anchor', 
    fieldDefaults: { 
     anchor: '80%', 
     allowBlank: true 
    }, 
    items: [ 

    { 
     xtype: 'textfield', 
     name: 'homePhone', 
     fieldLabel: 'Home phone number' 
    }, 
    { 
     xtype: 'textfield', 
     name: 'mobilePhone', 
     fieldLabel: 'Mobile phone number' 
    }] 
}, 
{ 
    xtype: 'fieldcontainer', 
    defaultType: 'textfield', 
    layout: 'anchor', 
    fieldDefaults: { 
     anchor: '80%', 
     allowBlank: true 
    }, 
    items: [ 
    { 
     name: 'address.id', 
     xtype: 'hidden' 
    }, 
    { 
     name: 'address.building', 
     fieldLabel: 'Building' 
    }, 
    { 
     name: 'address.street', 
     fieldLabel: 'Street' 
    }, 
    { 
     name: 'address.city', 
     fieldLabel: 'City' 
    }, 
    { 
     name: 'address.county', 
     fieldLabel: 'County' 
    }, 
    { 
     name: 'address.postcode', 
     fieldLabel: 'Postcode' 
    }, 
    { 
     name: 'address.country', 
     fieldLabel: 'Country' 
    } 
    ] 
}, 
] 

Beachten Sie die. Im Namensfeld, in dem das überschriebene setValues- und updateRecord-Formular bekannt ist, müssen diese Werte dem neuen Modell zugeordnet werden, das im Modell so definiert ist.

Ext.define('HOD.model.Employee', { 
    extend: 'Ext.data.Model', 
    fields: [ 
     // Person Class 
     // Auto 
     'id', 
     'name', 
     'homePhone', 
     'mobilePhone', 
     {model: 'HOD.model.Address', name: 'address'}, //Address 
     {model: 'HOD.model.Contact', name: 'iceInformation'} //Person 
    ] 
}); 

Ext.define('HOD.model.Address', { 
    extend: 'Ext.data.Model', 
    fields: [ 
     'building', 
     'street', 
     'city', 
     'county', 
     'postcode', 
     'country' 
    ], 
    belongsTo: 'Employee' 
}); 
+0

Dies ist eine interessante Lösung. Auch hier gibt es einen ähnlichen Thread über eine 2 viele Assoziationen hier: http://stackoverflow.com/questions/9871440/extjs-store-one2many-and-update-process-howto – dbrin

2

Es gibt keine verschachtelten Modelle, aber aus Ihrem Beispiel ist nicht klar, warum tun Sie das. Warum müssen Sie sowohl ID als auch Namen im Fahrzeugdatensatz speichern, wenn Sie diese Beziehung bereits in einer anderen Datenbank haben (ich nehme an, Sie haben etwas wie Brand Dictionary, wo Sie alle Paare ID/Name behalten?).

Update: Ich würde folgendes tun:

  • halten nur brand_id im Fahrzeug Rekord.
  • Wenn Sie ein Formular haben, vorhanden Combobox mit Werten aus dem Wörterbuch zu speichern und aktualisiert brand_id
  • Wenn Sie ein Gitter haben - definieren custom ‚Renderer‘ Funktion für die Spalte und Markennamen aus dem Wörterbuch Speicher erhalten durch brand_id

Hier ist Beispielcode für diese Spalte.

{ text: 'Brand Name', dataIndex: 'brand_id', 
    renderer: function(value) { 
     var rec = Ext.getStore('BrandDict').getById(value); 
     return rec ? rec.get('name') : ''; 
} 
+0

Sie haben Recht, ich habe Marken Wörterbuch. Ich muss die Namen aktualisieren, um den richtigen Wert im Raster anzuzeigen. Was mir bei diesem Ansatz nicht gefällt - ich muss alle Felder vom Markenmodell in das Fahrzeugmodell kopieren. In meinem Beispiel gibt es nur einen zusätzlichen Feldnamen, aber es kann noch viel mehr geben ... – mik

+0

Nein, tust du nicht. Wenn Sie sie nur im Grid anzeigen müssen, verwenden Sie einen benutzerdefinierten Renderer, aber bearbeiten Sie das gleiche Feld. – sha

+0

Ich verstehe Ihren Punkt mit Renderer nicht ganz. Können Sie erklären? – mik

Verwandte Themen