2012-03-27 6 views
3

のは、私はあなたがなど例えば 、車両モデルは、フィールドを持っている「brandId」、「新しい名称」を、見ることができるように、私は編集する車両ExtJSにして、ネストされたモデル

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'} 
    ] 

}); 

というモデルがあるとしましょうこのモデルのインスタンス 私は、 'brandId'フィールドにリンクされたコンボボックスを持つ編集フォームを作成します。 それから私は、それはすべてが正常に動作しますが、いくつかの外のモデルを表すすべてのフィールドに問題があるこの

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

とモデルのインスタンスにフォーム値を保存します。他のすべてのフィールドが、 だけのidのが更新されますidに依存するものは同じままです。

通常のOOP言語(Javaなど)では、CarBrandクラス を作成し、このクラスのインスタンスをVehicleクラスに配置します。 ExtJs 4にはhasMany関係がありますが、hasOneはありません。

このようなネストされたモデルのためのExtJS 4の最良のアプローチは何ですか?

答えて

10

4.0 * hasOneの関係をサポートしていません。 4.1はそれをサポートするためのものです。

4.0.7次のようなオーバーライドがあります。

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; 
    } 
}); 

これは私のフォームにありますので、名前を付けて作成します。

// 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' 
    } 
    ] 
}, 
] 

注意してください。名前フィールドには、オーバーライドされたsetValuesおよびupdateRecordフォームがモデルに定義されている新しいモデルにこれらの値をマップする必要があることがわかっています。

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

これは興味深い解決策です。また、ここに1つ2つの多くの関連についての同様のスレッドがあります:http://stackoverflow.com/questions/9871440/extjs-store-one2many-and-update-process-howto – dbrin

2

ネストされたモデルはありませんが、あなたの例ではこれをやっているのは明らかではありません。なぜあなたは既に他のデータベースでその関係を持っている場合、VehicleレコードにIDと名前の両方を保存する必要がありますか?(あなたはID /名前のペアをすべて保持するブランドディクショナリを持っていると仮定します)

更新:

  • 車両レコードでのみbrand_idしてください:私は次のことを行うだろう。列のカスタム「レンダラ」関数を定義し、brand_id
  • で辞書ストアからブランド名を取得する - あなたはフォームを持っている場合あなたは、グリッドを持っている場合
  • は、辞書ストアと更新からの値を持つ存在コンボボックスは
  • をbrand_id

はここで、このような列のサンプルコードです:。

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

私はブランドディクショナリーを持っています。グリッドに正しい値を表示するために、名前を更新する必要があります。このアプローチで私が気に入らないことは、ブランドモデルから車両モデルにすべてのフィールドをコピーする必要があります。私の例ではフィールド名は1つしかありませんが、もっと多くのものがあるかもしれません。 – mik

+0

いいえ、あなたはいません。グリッドに表示する必要がある場合は、カスタムレンダラーを使用しますが、同じコンボボックスフィールドを編集する必要があります。 – sha

+0

レンダラであなたのことをよく理解していません。説明できますか? – mik