2011-06-22 12 views
34

私は本当にバックボーンが好きですが、単純なものと思われるようなことをするのが最も難しい時です。私は次の例の助けを感謝します。Backbone.js配列の属性の処理

私は、私のUIにいくつかの項目の状態を保存するために使用するモデル、Criteriaを持っています。いくつかの単純な属性と、ユーザーがUIで選択したタグのIDを格納するために使用されるIDの配列である1つの属性があります。

したがって、私は新しいインスタンスを作成します。タグ配列にいくつかの項目を追加します。次に、同じ変数に割り当てられた、新しいインスタンスを作成し直したいと思います。しかし、私のタグ配列は、それが私がCriteriaの最初のインスタンスの一部として追加した情報を保持し続けています。

以下のテストケースを文書化しました。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <title>Test</title> 
    <script src="Scripts/Libraries/jquery-1.6.1.js" type="text/javascript"></script> 
    <script src="Scripts/Libraries/underscore.js" type="text/javascript"></script> 
    <script src="Scripts/Libraries/backbone.js" type="text/javascript"></script> 

    <script language="javascript" type="text/javascript"> 

     $(function() { 

      // Simple model to hold some state about my UI. 
      var Criteria = Backbone.Model.extend({ 

       defaults: { 
        "status": "Normal", 
        "priority": "Normal", 
        "tags": new Array() 
       } 

      }); 

      // Create new criteria. 
      window.criteria = new Criteria(); 

      // The length of the tags array should be 0. PASSES 
      console.log("Expect 0: Actual " + window.criteria.get("tags").length); 

      // Add a tag id to the tags array. 
      window.criteria.get("tags").push(5); // Tag with ID of 5. 

      // The length of the tags array should be 1. PASSES 
      console.log("Expect 1: Actual " + window.criteria.get("tags").length); 

      // Create a new instance of criteria. 
      window.criteria = new Criteria(); 

      // The length of the tags array should be 0. FAILS 
      // CONFUSED. I thought this is now a new instance with a new set of attributes. 
      // Why does the tags collection still have an item in it. 
      console.log("Expect 0: Actual " + window.criteria.get("tags").length); 

      // OK. So, I will call the clear method on the model. This is supposed to remove all attributes 
      // from the model. 
      // Then, I will create it again. 
      window.criteria.clear(); 
      window.criteria = new Criteria(); 

      // The length of the tags array should be 0. FAILS. Still 1. 
      console.log("Expect 0: Actual " + window.criteria.get("tags").length); 

      // ARGH! 
      console.log("HELP!"); 

     }); 

    </script> 

</head> 
<body> 
    <h1>Test</h1> 
    <p>Backbone test page.</p> 
</body> 
</html> 

私はちょうどここのマークオフですか?バックボーンを意図せずに使用しようとしていますか?または、私はJavaScriptのオブジェクト指向プログラミングでもっと一般的なものを見逃していますか?

P.S.もともと私は、タグのバックボーンコレクションを使用していましたが、それは、複数のコレクションで参照されるタグモデルと、アイテムがコレクションから削除されたときに、バックボーンのremoveメソッドが "コレクション"リファレンスをどのように設定解除するかに関する、別の日、別の問題。

+0

こんにちはKevin、おそらくあなたはあなたの受け入れられた答えをその下のものに変更することができますか?これははるかに読みやすく、推奨されるアプローチです。受け入れられた答えは、とにかく同じものの膨張したアイデアだけです。ありがとう。 – SuperDuperApps

答えて

34

トム・ブレイクが、それは同じ値を保っている理由についての権利であります配列。これを解決するための1つのオプションは、イニシャライザのデフォルト値を設定することです。

 var Criteria = Backbone.Model.extend({ 

      defaults: { 
       "status": "Normal", 
       "priority": "Normal" 
      }, 

      initialize: function(){ 
       if(!this.get('tags')){ 
       this.set({tags: new Array()}); 
       } 
      } 

     }); 
+8

+1これを処理するバックボーンの方法を示します。 –

+0

ありがとうございます。私はこのアプローチに従うことになり、今は完璧な意味があります。ですから、基本的な値(ステータス、優先度)をタグ配列のようにリセットする必要はありませんか?正しい? – Kevin

+0

@ケビン正しい。 –

13

'defaults'の下に 'tags'を定義すると、新しいArrayを作成し、そのクラスのデフォルト値に設定します。次に、新しいインスタンスを作成するときに、同じ配列参照がありますが、それにはまだプッシュされたものが含まれています。

ではなく、タグのデフォルト値を設定し、あなたはそれを最初に使用する前に、ちょうど[]に設定することができるはずです。

window.criteria = new Criteria() 
window.criteria.set({'tags', []}) //you can use new Array() if you want 
window.criteria.get('tags').push(5) 

window.criteria = new Criteria() 
console.log(window.criteria.get('tags')) //should be undefined 
window.criteria.set({'tags', []}) 
+2

最近、js DateオブジェクトをBackbone.Model型クラスのプロパティとして格納するときに同じ問題が発生しました。私は、単一の参照を変更するだけで、新しい日付オブジェクトを作成していませんでした。バックボーンが関係する限り、日付は決して変更されず、イベントは決して解雇されませんでした。ルールは、バックボーンで常に不変の値としてプロパティを扱います。プロパティを変更する必要がある場合は、新しい参照を作成し、新しい参照を変更する新しい値を複製します。 – bradgonesurfing

+0

私は先に進み、以下の初期化の方法に従った。良い説明。ありがとう! – Kevin

70

"defaults"は関数でもあります。

var Criteria = Backbone.Model.extend({ 
    defaults: function() { 
     return { 
      "status": "Normal", 
      "priority": "Normal", 
      "tags": new Array() 
     } 
    } 
}); 

これは、新しい基準がインスタンス化されると、新しい配列を作成します。 参照:http://backbonejs.org/#Model-defaults

+0

返品の目的は何ですか? – Tjorriemorrie

+10

キーは、 "defaults"プロパティがオブジェクトではなく関数であることです。戻り値は、関数から返され、 "デフォルト"の値として使用されるオブジェクトを示します。 他の人が説明したように、 "defaults"がオブジェクトの場合、新しいモデルが作成されると、 "defaults"の各プロパティがオブジェクトの属性にコピーされます。プロパティが文字列または数値の場合、これは期待通りに機能しますが、オブジェクトおよび配列では、このコピーは参照によって行われます。各インスタンスがデフォルト属性の独自のコピーを持つためには、関数を使用する必要があります。 – btford

+7

私は選択した答えの構文よりも、この構文を好むでしょう。 – Pablote

3

明らかに、Maksym H.が提供する最後のオプションは問題を解決しません。すべての値セットが不変であると仮定して、defaultsプロパティーが提供されます。ただし配列は変更可能であり、値を変更することができます(tags [0] = "hello"はタグ[0] = "hi there"で変更できます)。

btfordの答えを使用すると、モデルの新しいインスタンスごとに変更可能なオブジェクト/プロパティの新しいインスタンスが作成されるため、オブジェクトは関数スコープの変数で作成されるため共有されません。

同様に、Derick Baileyの回答は正しいですが、defaultsメソッドの代わりにinitializeメソッドを使用するだけです。