2016-04-23 13 views
1

ExtJsで独自のカスタムタイプを定義する最善の方法を探しています。 私はフォーム、グリッド、ピボットなどでそれを使用したいと思います。それは、独自のレンダリング、計算、ソートの動作を持っている必要があります。ExtJS:完全に機能するカスタムタイプ

「ペース」タイプを考えてみましょう。ペースは、距離の単位で移動するのに必要な時間の長さとして定義されます。たとえば、ペース2:30は、1マイルまたはkmを実行するのに2分30秒が必要であることを意味します。 ペースを追加(2:30 + 2:35 = 5:05)し、他の計算に使用することができます。 ペースが小さいほどペースが速く、ペース2:00は2:30より速く(高い)ことを意味します。

だから、私の知る限り、これは独自のカスタムタイプを定義し、以下のコードのように、データモデルにそれを使用する方法です:

Ext.define('App.fields.Pace', { 
    extend: 'Ext.data.field.Field', 
    alias: 'data.field.pace' 
}); 

Ext.define('Data', { 
    extend: 'Ext.data.Model', 
    fields: [ 
     {name: 'id'},       
     {name: 'pace', type: 'pace'} 
    ] 
}); 

このような定義された型がダミーの一つであり、それはレンダリングされません。 、並べ替え、または正しく計算します。

これを拡張する方法はありますか?フォーム、グリッド、ピボットなどで問題なく動作しますか? アーカイブするにはどうすればよいですか?いくつかのメソッドを定義したり上書きしたりすべきですか? または、他の同様のタイプ(たとえば日付)を継承したり、テンプレートとして使用したりする必要がありますか? 私は最低限新しいカスタムタイプはintのような内部型にその値を変換するメソッドを提供する必要があり、この内部的な値を外部フォーマットとしてレンダリングするメソッドがありますが、そのようなメソッドは見つかりません。

標準タイプを使用できるすべてのシナリオで正しく機能する独自のタイプを定義することはできますか?

よろしく、 アニー

答えて

0

私は、カスタムタイプで計算すると、ExtJSの中でサポートされているとは思いません。任意の関数を任意のクラスに拡張してカスタム計算機能を実装できますが、私はnot sure you can override operators in JavaScriptです。

Ext.define('Ext.data.field.Array',{ 
    extend: 'Ext.data.field.Field', 
    getType: function() { 
     return "array" 
    }, 
    compare: function(o1, o2) { 
     if (!o1 && !o2) { 
      return 0 
     } 
     if (!o1) { 
      return -1 
     } 
     if (!o2) { 
      return 1 
     } 
     if (o1.length != o2.length) { 
      return o1.length > o2.length ? -1 : 1 
     } 
     for (var i = 0; i < o1.length; i++) { 
      if (o2.indexOf(o1[i]) == -1) { 
       return 1; 
      } 
     } 
     return 0 
    }, 
    convert: function(value) { 
     if (this.separator && Ext.isString(value)) { 
      if (value == "") { 
       value = [] 
      } else { 
       value = value.split(this.separator) 
      } 
     } 
     if (Ext.isArray(value)) { 
      if (this.map) { 
       value = value.map(this.map) 
      } 
      return value 
     } 
     return [] 
    }, 
    serialize: function(value) { 
     if (Ext.isArray(value)) { 
      if (!this.allowBlank) { 
       value = Ext.Array.filter(value, function(a) { 
        return a !== "" 
       }) 
      } 
      if(this.separator) return value.join(this.separator) 
      else return value 
     } 
     return value 
    } 
}); 

モデルにおける典型的なフィールドの定義は次のことがあります:

ことができるだろう
{ 
    name: "Names", 
    type: "array", 
    allowBlank: false, 
    separator: "," 
} 

私はあなたにカスタム型arrayの例をあげてみましょう、と述べた

JSON配列またはコンマ区切りの文字列を解析し、サブミットするためにコンマで区切られた文字列にシリアル化するか、

{ 
    name: "Attachments", 
    type: "array", 
} 
0 JSON配列を解析し、アレイにシリアライズすることができるであろう

、または

カンマで区切られた文字列を取得し、それが配列を返すように、モデルにそれのすべての部分をマッピングない
{ 
    name: "Categories", 
    type: "array", 
    separator:',', 
    map:function(value) { 
     return Ext.create('MyApp.model.Category',{value:value}); 
    } 
} 

モデルの。

この値はソート、シリアライズ、およびデシリアライズを行いますが、レンダリングはしません。レンダリングは型によって行われるのではなく、型を使用するExt.Componentによって行われます。 gridcolumnまたはフォームフィールド。 datecolumndatepickerfieldnumbercolumnおよびnumberfield(AKA spinner)、checkcolumnおよびcheckboxfieldという理由があります。

私の配列では、comboboxmulti:trueの適切なフィールドがありますが、私はカスタムレンダラーを持つカラムが必要です。それでは、arraycolumnを作ってみましょう:もちろん保証もない現状

Ext.define('MyApp.ux.ArrayColumn',{ 
    extend:'Ext.grid.column.Column', 
    lines: 6, 
    renderer:function(value) { 
     if (Ext.isString(value)) { 
      value = value.split("\n") 
     } 
     var len = value.length; 
     if (this.lines && len > this.lines) { 
      value = value.slice(0, lines - 1); 
      value.push('and {n} more...'.replace('{n}', len - lines + 1)) 
     } 
     return value.join("<br>"); 
    } 
}); 

すべて、...

0

複合型(またはルールを持つもの)は、一般的にモデル化されているとしてそれはアンチパターンのビットのように感じていますそのような実体はone-to-one associationsを使用してレコードに添付することができます。しかし、あなたの質問では、これは私が思い付くことができる最も単純な実装です。

» Fiddle

理想的には私は、整数として値を正規化して保存するのが好きのだろう。 "ペース"の最低金種すなわち合計秒数。残念なことに、ExtJSフィールドタイプは、APIの他の部分と自動的に連動する書式設定フックを提供しないので、文字列操作が必要です。

次のフィールドクラスには、数字入力または文字列入力を整数に縮小するカスタムgetValue関数が含まれています。他の関数は基本クラスのメンバをオーバーライドし、フレームワークによって自動的に呼び出されます。

convertは、データがモデルに読み込まれたときに呼び出され、入力の整合性を暗黙的に検証するためにここで使用されます。 sortTypeは、コレクションでさまざまなソーターを使用するたびに呼び出され、文字列をあいまいでない/簡単に匹敵する値に減らすためにここで使用されます。

Ext.define('App.data.field.Pace', { 
    extend: 'Ext.data.field.Field', 
    alias: 'data.field.pace', 
    isPace: true, 

    getValue: function(v){ 
     var type = typeof v, 
      isNan = isNaN(v); 
     if(type === 'number' || !isNan) 
      return isNan ? 0 : (+v|0); 
     if(type === 'string'){ 
      var match = v.match(/^(\d+):([0-5]?\d)$/); 
      if(match) 
       return (+match[1]) * 60 + (+match[2]); 
     } 
     return 0; 
    }, 

    convert: function(v){ 
     var proto = App.data.field.Pace.prototype, 
      value = proto.getValue(v), 
      mins = value/60 | 0, 
      secs = value % 60; 
     return String(mins) +':'+ (secs<10?'0':'') + String(secs); 
    }, 

    sortType: function(v){ 
     var proto = App.data.field.Pace.prototype; 
     return proto.getValue(v); 
    } 
}); 

全ての機能を故意にクラスプロトタイプを介して代わりにthisキーワードからアクセスされていることを注意 - 様々な時点で - - た場合には(独立に任意のフィールド機能を呼び出すために好きなフレームワークがあるかのようにその周りに再生を見ながら任意の)インスタンス化されたクラスであるため、バインドされたコンテキストに頼らないことをお勧めします。

フィールド値の加算/演算に対処するには、calculateの設定を利用することができますが、これは実際のカスタムフィールドタイプを使用しているモデル内に存在する必要があります。たとえば、

Ext.define('App.data.Model', { 
    extend: 'Ext.data.Model', 

    fields: [ 
     { 
      name: 'name', 
      type: 'string' 
     }, 
     { 
      name: 'paceOne', 
      type: 'pace' 
     }, 
     { 
      name: 'paceTwo', 
      type: 'pace' 
     }, 
     { 
      name: 'paceTotal', 
      type: 'pace', 
      calculate: function(data){ 
       var proto = App.data.field.Pace.prototype; 
       return proto.convert(
        proto.getValue(data.paceOne) + 
        proto.getValue(data.paceTwo) 
       ); 
      } 
     } 
    ] 
}); 
関連する問題