2012-06-30 53 views
1

我有几个不同的问题正在进行,我希望这个例子很容易遵循。该代码使用HTML模板,默认情况下隐藏元素(使用CSS)。 Backbone View使用模型中的数据显示适当的值,或者如果模式中没有值,则隐藏UI元素。Backbone.js - 视图和模型之间的关系?

鉴于这里的一切在默认情况下(使用CSS)隐藏的模板,例如:

<script type="text/template" id="Person-Template"> 
    <span class="fname" title="FirstName"></span> 
    <span class="lname" title="LastName"></span> 
    <span class="age" title="Age"></span> 
</script> 

要隐藏的每个UI元素的CSS是:将

span.fname, 
span.lname, 
span.age { 
    display:none; 
} 

我Backbone.js的型号因此是:

PersonModel = Backbone.Model.extend({ 
     defaults: { 
      fname: undefined, 
      lname: undefined, 
      age: undefined 
     } 
    }); 

观(简化的)将是:

PersonView = Backbone.View.extend({ 
    tagName: 'div', 

    initialize: function() { 
     this.model.on("fname", this.updateFName, this); 
     this.model.on("lname", this.updateLName, this); 
     this.model.on("age", this.updateAge, this); 
    }, 

    updateFName: function() { 
     // Pseudo code 
     Get 'new' value from Model 
     Obtain reference to DOM element span.fname 
     Update span.fname 

     if (model value is empty) { 
      Hide UI element. 
     } 
    }, 

    updateLName: function() { 
     // Same as above 
    }, 

    updateAge: function() { 
     // Same as above 
    }, 

    render: function() { 
     // Get model values to display 
     var values = { 
      FirstName : this.model.get('fname'), 
      LastName : this.model.get('lname'), 
      Age: this.model.get('age'), 
     }; 

     // Load HTML template 
     var template = $('#Person-Template').html(); 

     // Populate template with values 
     var t = _.template(template, values); 

     // Show/hide UI elements 
     this.updateFname(); 
     this.updateLName(); 
     this.updateAge(); 
    } 

}

最后一个问题:它似乎哈克呼召呈现每个updateXYZ()()方法只是确定是否隐藏或显示的UI元素进行设置。我的模型中有很多属性,代码看起来真的很荒谬。

I have been told on SO该视图不应该负责确定应该或应该显示什么。我的问题是,那么什么是负责任的?用户可以执行一些清除名字的(有效)声调,在这种情况下,我不希望我的视图显示“名字:”,后面没有值。

+0

您可以在模板中使用if语句来有条件地显示HTML块。 下面是关于SO的一个例子: http://stackoverflow.com/questions/7230470/how-to-use-if-statements-in-underscore-js-templates – Chris

回答

3

首先,你不需要建立自己的values手,只需使用toJSON

var values = this.model.toJSON(); 

然后,你必须添加您填写模板到您的视图的el

this.$el.html(_.template(template, values)); 

和模板大概应该包括的东西在你的模板来显示:

<script type="text/template" id="Person-Template"> 
    <span class="fname" title="FirstName">F: <%= fname %></span> 
    <span class="lname" title="LastName">L: <%= lname %></span> 
    <span class="age" title="Age">A: <%= age %></span> 
</script> 
现在回到你的活动

_(values).each(function(v, k) { 
    var m = _(v).isUndefined() ? 'hide' : 'show'; 
    this.$('.' + k)[m](); 
}, this); 

你不为三个部分在render独立的功能,你可以通过它们只是循环。除非你添加了一个自定义的事件,否则不会有这样的事件。但没有必要,fname更改时,模型将触发"change""change:fname"事件;你只需要关心"change"虽然:

initialize: function() { 
    _.bindAll(this, 'render'); 
    this.model.on("change", this.render); 
}, 

我也必将render到您的视图实例使用_.bindAll,这样你就不必担心的第三个参数this.model.on

现在你有一些作品:http://jsfiddle.net/ambiguous/46puP/


您也可以按下 “这应该显示” 逻辑到模板:

<script type="text/template" id="Person-Template"> 
    <% if(fname) { %><span class="fname" title="FirstName">F: <%= fname %></span><% } %> 
    <% if(lname) { %><span class="lname" title="LastName">L: <%= lname %></span><% } %> 
    <% if(age) { %><span class="age" title="Age">A: <%= age %></span><%   } %> 
</script> 

,简化您的render

render: function() { 
    var values = this.model.toJSON(); 
    var template = $('#Person-Template').html(); 
    this.$el.html(_.template(template, values)); 
    return this; 
} 

演示:http://jsfiddle.net/ambiguous/W9cnJ/

这种方法可能是最常见的,它没有任何问题。我认为你误解了以前的答案试图告诉你。该模板已选择通过<%= ... %>显示哪些信息,因此没有理由认为在尝试显示fname之前不应该看到它。根据数据的性质,您可能希望在模板中使用if(!_(fname).isUndefined())等,但简单的真实性检查可能没有问题;在某些情况下,age可能会成为问题,尽管如此,您可能希望对此稍加严格。

+0

我不使用toJSON()的原因是因为该模型具有一些“复杂”属性(即其他模型)。我知道生成的JSON只包含嵌套的objets,但我的模板不是'嵌套的' - 它们是单独的模板。因此,我实际上不需要JSON中包含的“复杂”嵌套属性。 – Jack

+0

@Jack:在这种情况下,我建议在你的模型中添加一个方法来简化'toJSON'。但是你的问题的那部分是相当小的。 –