0

問題は、'name' 以外のすべてのオブジェクト属性が、テンプレートからアクセスしたときにコンソールでエラー 'id/url/whatever is not defined' を呼び出すことです。「名前」だけのテンプレートは問題なく表示され、正しい名前が表示されますが、別の属性を呼び出すとすぐに、たとえば. idまたはurl、壊れます。ビューに渡されるオブジェクトは、解析された静的 JSON ファイルであり、すべてのアイテムが同じレベルにあり、コンソールからアクセスできます。collectionName.models[0].get('id');

私が混乱したのは、 name 属性が、バックボーン/アンダースコアコードのどこかにデフォルトとして事前定義されているかのように機能することです。

非常に明白な何かが欠けていますか?コンソールからモデルデータにアクセスできるので、ビュー自体のデータの扱い方に問題があると思いますが、いくつかの方法で書き直してみましたが、違いはないようです。


関連するすべてのコード。

渡されたオブジェクト形式。これはcollectionName.models[0].attributes;、コンソールに返されるものでもあります。

[{
"id":"0",
"name": "Building1",
"url": "building_1",
"floors":[{
    "id":"0",
    "name":"Ground Floor",
    "image":"",
    "rooms":[{
        "id": "r_1",
        "name": "Room 1",
    },
    {
        "id": "r_2",
        "name": "Room 2"
    }]
}
}]

}

テンプレート コードの例:

<span class="name"><%= name %></span>
<%= id %> <%= url %>

ルーターコード:

routes: {
  '': 'intro', // this route is using pretty much identical code and works fine, the model has the exact same format, the only difference is that all attributes work.
  ':id': 'firstLevel'    
},

firstLevel: function  (id) {
  window.singleBuilding = new ThisBuilding({}, {idBuilding: id});

  window.singleBuilding.fetch();      

  this.floorView = new FloorList({
    collection: window.singleBuilding
  });

  var $intro = $('#intro');
  $intro.empty();
  $intro.append(this.floorView.render().el);
}

ビュー:

window.FloorSingleList = Backbone.View.extend({

  className: 'floor-list',

  initialize: function  () {

  this.template = _.template(tpl.get('floors-list-item')); 
  _.bindAll(this, 'render');
  this.model.bind('change', this.render);
  this.testModel = this.model.attributes; // I tried passing the attributes directly to the templatewithout .toJSON(), which worked exactly the same, as in only the 'name' attribute worked
},

render: function  () {
  console.log("The test data is:", this.testModel);
  console.log("The actual model data is:", this.model);
  var renderedContent = this.template(this.model.toJSON());
  $(this.el).html(renderedContent);

  return this;
 }

});

window.FloorList = Backbone.View.extend({

tagName: 'section',
className: 'intro-list',

initialize: function () {

  this.template = _.template(tpl.get('intro-list'));
  _.bindAll(this, 'render');
  this.collection.bind('reset', this.render, this);
  this.collection.bind('change', this.render, this);
},

render: function  (eventName) {

     var $introList;
     var collection = this.collection;

  $(this.el).html(this.template({ }));
  $introList = this.$('.intro-list');
  collection.each(function (building) {
    var view = new FloorSingleList({
      model: building,
      collection: collection
    });
    $introList.append(view.render().el);
  });

  return this;
}

});

モデルコード:

window.ThisBuilding = Backbone.Collection.extend({

model : Building,

initialize: function(models, options) {
  // Initialising the argument passed on from the router.
  this.idBuilding = options.idBuilding;
  return this;
},

url : function(){
  return  "data.json"      
},

parse: function (response) {
  console.log("Passed parameters are :", this.idBuilding); // Returns the request parameters passed from the router.
  return response[this.idBuilding];
}

});

テンプレートとブートストラップ

// templates are loaded during the bootstrap 
tpl.loadTemplates(['header', 'intro-list', 'floors-list-item', 'building-list-item'], function() {
    window.App = new ExampleApp();
    Backbone.history.start();
});
4

1 に答える 1

0

問題は、JavaScriptでのフェッチがどのように非同期であるかにあります...

firstLevel: function  (id) {
  window.singleBuilding = new ThisBuilding({}, {idBuilding: id});

  window.singleBuilding.fetch();  // YOU FETCH HERE     

  this.floorView = new FloorList({
    collection: window.singleBuilding
  });

  var $intro = $('#intro');
  $intro.empty();
  $intro.append(this.floorView.render().el); // AND RENDER WHILE YOU CAN'T ASCERTAIN THE FETCH HAS BEEN COMPLETED...
}

つまり、レンダリングは、まだ適切に初期化されていないコレクションを読み取ろうとします->モデルはまだ完成していません->おかしな読み取りです。非同期操作に関しては、コンソールログは黒魔術で機能します。だからそれはおそらくあなたに何かを伝え、現実は完全に異なるものですそれで代わりにこれをしてください:

firstLevel: function  (id) {
  window.singleBuilding = new ThisBuilding({}, {idBuilding: id}); 

  // Don't fetch here...   

  this.floorView = new FloorList({
    collection: window.singleBuilding
  });

  var $intro = $('#intro');
  $intro.empty();
  $intro.append(this.floorView.el); // Don't render here
}

そして、FloorList-viewで:

initialize: function () {

  this.template = _.template(tpl.get('intro-list'));
  _.bindAll(this, 'render');
  this.collection.bind('reset', this.render, this);
  this.collection.bind('change', this.render, this);
  this.collections.fetch(); // fetch here, your binds take care of rendering when finished
}

更新2:どうやら私は何もなかったところに複雑さを見ました...以下のすべてを無視してください

Backbone.jsドキュメントからModel.toJSON()

JSON文字列化のためにモデルの属性のコピーを返します。

したがって、属性をJSONとして返します。現在、バックボーンは次のように定義idされています

モデルの特別なプロパティ...

属性ではなく、プロパティ。URLについても同じことが言えます。バックボーンモデルを表すjavascriptオブジェクトでは、属性はオブジェクト内の独自のオブジェクトに格納され、idプロパティとurlプロパティはモデルオブジェクトの他の場所に格納されます。たとえば、モデルを表すjavascriptオブジェクトは次のようになります。

{
  ...
  attributes: Object // this is where your name attribute lives
  ...
  id: 34, // this is your id property
  ...
  __proto__: ctor, // this is where your url-function resides
  ...
}

更新:id-propertyはJSONに埋め込まれていますmodel.toJSON()

したがって、これを行うときはthis.model.toJSON()、model-objects attribute-propertyのコンテンツからJSONを作成し、id-propertyを含めます。url-propertyはこれに含まれていません。たとえば、できること:

var renderedContent = this.template({
  attributes: this.model.toJSON(),
  url: this.model.url()
});

とテンプレートで

<span class="name"><%= attributes.name %></span>
<%= attributes.id %> <%= url %>

お役に立てれば!

于 2012-07-31T12:16:13.147 に答える