5

ユーザーが最後に特定のものを選択するのに役立つと思われるフォームがありますが、ユーザーが最初のオプションを入力すると、以下の他のオプションが変更されます。このようなもの:

Type:
{
    t1:{
        Number of X:{
            1:{...}
            2:{...}
        }
        Number of Y:{...}
    }
    t2:{
        Number of X:{
            100:{...}
            200:{...}
        }
        Number of Y:{...}
    }
}

ユーザーは、オプションt1およびt2を含むフィールドTypeを持っています。t1を選択すると、フィールド「Number of X」は1および2で埋められ、t2を選択すると、フィールド「NumberofX」は100で埋められます。および200など。一部の選択肢は複数のフィールドに依存しており、直接的な依存関係ではありません(たとえば、ユーザーが「Number of X」=100を選択した場合、Fooは「A」です。それ以外の場合、Fooは「A」、「B」になります。または「C」ですが、Fooは「NumberofX」より下ではありません)。

すべてのフィールドにイベントリスナーを設定してその変更を確認するという非常に単純な実装を試しましたが、最終的にコードが制御不能になり始め、$("#foo").change(function(){...});これをリッスンしているフィールドがそうであるかどうかはすぐにはわかりbarません。 fbar

JSONも(上記の例のように)試しましたが、繰り返しが多く、ツリーが深くなり、可能性のあるものの数が増えるため、同じフィールドを何度も書き込む必要があります。選択t1すると、オプションが直接下にない場合でも、通常は別のフィールドに完全に依存している場合でも、オプションが直接変更されることがあります。これは、JSONでの繰り返しです。

この問題にどのようにアプローチしますか?読みやすい解決策はありますか?コードを見て依存関係とその影響を理解できる限り、コードが多すぎても問題はありません。

コード例(今の私のコードのようなもの):

HTML:

<select id="type">
<option value=1>a</option>
<option value=2>b</option>
</select>
<select id="numOfX">
</select>
<select id="numOfY">
</select>

js:

$("#type").change(function()
{
    if($("#type").val() == 1)
    {
        $("#numOfX").append(new Option(1, "1", false, false));
        $("#numOfX").append(new Option(2, "2", false, false));
    }
    else if($("#type").val() == 2)
    {
        $("#numOfX").append(new Option(1, "100", false, false));
        $("#numOfX").append(new Option(2, "200", false, false));
    }
});

$("#numOfX").change(function()
{
    ...
});
4

2 に答える 2

1

更新-例を追加

backbone.jsライブラリを試しましたか?モデルと構造を追加することで、Javascriptコードをより管理しやすくします。学習曲線はありますが、それは本当に素晴らしいです。バックボーンを学習したら、ドロップダウン管理に役立つバックボーンフォームプラグインを利用できます。以下は、デモリンクとサンプルコードです。

例1

$(function() {
var cities = {
    'UK': ['London', 'Manchester', 'Brighton', 'Bristol'],
    'USA': ['London', 'Los Angeles', 'Austin', 'New York']
};

var subAreas = {
    'London' : ['L1', 'L2', 'L3', 'L4'],
    'Manchester' : ['M1', 'M2', 'M3', 'M4'],
    'Brighton' : ['B1', 'B2', 'B3', 'B4'],
    'Bristol' : ['BR1', 'BR2', 'BR3', 'BR4'],
    'Los Angeles' : ['LA1', 'LA2', 'LA3', 'LA4'],
    'Austin' : ['A1', 'A2', 'A3', 'A4'],
    'New York' : ['NY1', 'NY2', 'NY3', 'NY4']
};


//The form
var form = new Backbone.Form({
    schema: {
        country: { type: 'Select', options: ['UK', 'USA'] },
        city: { type: 'Select', options: cities.UK },
        subArea: { type: 'Select', options: subAreas[cities.UK[0] ] }
    }
}).render();

form.on('country:change', function(form, countryEditor) {
    var country = countryEditor.getValue(),
        newOptions = cities[country];

    form.fields.city.editor.setOptions(newOptions);

    var city = newOptions[0],
        areaOptions = subAreas[city];

    form.fields.subArea.editor.setOptions(areaOptions);

});

form.on('city:change', function(form, cityEditor) {
    var city = cityEditor.getValue(),
        newOptions = subAreas[city];

    form.fields.subArea.editor.setOptions(newOptions);
});

//Add it to the page
$('body').append(form.el);

}); </ p>

例2

$(function() {
var cities = {
    'UK': ['London', 'Manchester', 'Brighton', 'Bristol'],
    'USA': ['London', 'Los Angeles', 'Austin', 'New York']
};

var subAreas = {
    'UK.London' : ['L1', 'L2'],
    'USA.London' : ['L3', 'L4'],
    'UK.Manchester' : ['M1', 'M2', 'M3', 'M4'],
    'UK.Brighton' : ['B1', 'B2', 'B3', 'B4'],
    'UK.Bristol' : ['BR1', 'BR2', 'BR3', 'BR4'],
    'USA.Los Angeles' : ['LA1', 'LA2', 'LA3', 'LA4'],
    'USA.Austin' : ['A1', 'A2', 'A3', 'A4'],
    'USA.New York' : ['NY1', 'NY2', 'NY3', 'NY4']
};

var hashFunc = function(country, city){
    return country + "." + city;
};


//The form
var form = new Backbone.Form({
    schema: {
        country: { type: 'Select', options: ['UK', 'USA'] },
        city: { type: 'Select', options: cities.UK },
        subArea: { type: 'Select', options: subAreas[ 'UK.London' ] }
    }
}).render();

form.on('country:change', function(form, countryEditor) {
    var country = countryEditor.getValue(),
        newOptions = cities[country];

    form.fields.city.editor.setOptions(newOptions);

    var city = newOptions[0],
        areaOptions = subAreas[hashFunc(country, city) ];

    form.fields.subArea.editor.setOptions(areaOptions);

});

form.on('city:change', function(form, cityEditor) {

    var city = cityEditor.getValue(),
        newOptions = subAreas[hashFunc(form.getValue().country, city)];

    form.fields.subArea.editor.setOptions(newOptions);
});

//Add it to the page
$('body').append(form.el);
});​

モバイル(おそらくPhonegap)向けにも開発しているので、jQueryの代わりにZeptoJSを試すこともできます。それは速度を大幅に改善します。

于 2012-11-12T18:24:18.190 に答える
1

概説されているタスクは依存関係のために複雑であるため、依存関係を定義する方法を考える必要があります。これが私がそれをする一つの方法です:

  • データを処理するモデルを定義します。
  • 依存関係を定義します。
  • 依存関係を管理します。

以下に、これがすべて実装されていることを確認する概念モデルを示します(私の回答の最後に、この擬似コードで提供されていないものについて説明します)。

//data/model structure for Type.
var type = {
    //list all values.
    values: [
        { id: 1, text: 't1', visible: true },
        { Id: 2, text: 't2', visible: true }
    ],

    //evaluates visibility of item using dependencies.
    //depends on nothing, so takes no arguments except item.
    evaluate: function(item) {
        return; //depends on nothing.
    },

    // this event fires when selected item changes.
    onChange: event

};

//data/model structure for number of X.
var numberOfX = {
    //list all values.
    values: [
        { id: 1, text: '1', visible: true },
        { id: 2, text: '2', visible: true },
        { id: 3, text: '100', visible: true },
        { id: 4, text: '200', visible: true }
    ],

    //evaluates visibility of item using dependencies.
    //since numberOfX depends on Type, it takes type as second argument.
    //it would take more arguments if it depended on other things too.
    evaluate: function(item, type) {
        // next line will fire onChange event.
        item.visible = 
        ( [1,2].indexOf(item.id) >=0 && type.id == 1 ) ||
        ( [3,4].indexOf(item.id) >=0 && type.id == 2 );
    },

    // this event fires when selected item changes.
    onChange: event
};

//data/model structure for number of Y.
var numberOfY = { /* omitted. This is similar to the previous ones */ }


//numberOfX depends on Type.
//if it depended on more objects, then we would pass them as additional arguments.
register_dependency(numberOfX, type);
//numberOfY depends on Type.
register_dependency(numberOfY, type);
//... etc: define other dependencies.

JavaScriptにはイベントメカニズムはありませんが、実装は難しくありません。そのためのフレームワークも使用できます。

register_dependency関数は、以下で説明するように(依存関係の管理) 、イベントに登録するだけで依存関係のグラフを作成します。

onChangeいずれかのモデルでイベントが発生するとevaluate、依存関係ツリーのアイテムごとにが呼び出されます。たとえば、type.onChange火事のとき、私たちはnumberOfXnumberOfYオブジェクトを持っています。それらのvalues配列はループで列挙され、evaluateアイテムごとに呼び出されます(受け渡しitemおよびtype引数として)。

結論:このコードは複雑に見えますが、それでもより自己記述的であり、ページ上の複数のオブジェクト間の依存関係のグラフを作成できます。また、すべての複雑さはツールキット/フレームワークレベルにあり、一度だけ実装すると簡単に再利用できます。

編集:この種のモデルにバインドしてページに表示するには、何らかのメカニズムが必要になることを概説するのを忘れましたが、これも簡単です。たとえば、knockout.jsを見てください。

于 2012-11-12T19:55:42.770 に答える