2013-04-24 71 views
1

我正在学习KO并尝试创建一个简单的列表项添加/删除。但我有以下问题。 Q1:如果您单击添加而不输入名称,则您刚刚添加的项目将具有result作为名称。为什么以及如何防止它,同时允许空作为有效的输入?问题2:我想用<pre>标签来显示当前视图模型的JSON,但它没有显示任何内容。但按钮显示的东西。 我想出了这一个。我需要使用ko.toJSON($data, null, 4)绑定和ko.toJSON不按预期工作

Q3:它与Q2相关,按钮显示某些内容,但它显示的内容似乎很奇怪。输入几个项目后,点击debug按钮。您会看到视图模型中的所有项目都被您更改的最后一个项目替换。

这是fiddle

CSS:

input[type=text], select { 
    width:100px; 
} 

JS:

function foodie() { 
    this.name; 
    this.food; 
} 

function foodieApp() { 
    var self = this; 
    self.foodies = ko.observableArray(); 
    self.foodieToAdd = ko.observable(new foodie()); 

    self.addFoodie = function() { 
     this.foodies.push(this.foodieToAdd()); 
    }; 

    self.delFoodie = function (foodieToDel) { 
     self.foodies.remove(foodieToDel); 
    }; 

    self.debug = function() { 
     alert(ko.toJSON(self, null, 4)); 
    }; 
} 

var app = new foodieApp(); 
ko.applyBindings(app); 

HTML:

<table> 
    <thead> 
     <tr> 
      <td>Foodie's Name 
       <br/> 
       <input type=text data-bind='value: foodieToAdd().name' /> 
      </td> 
      <td>Foodie's Food 
       <br/> 
       <select data-bind='value: foodieToAdd().food'> 
        <option value=apple>Apple</option> 
        <option value=banana>Banana</option> 
        <option value=cherry>Cherry</option> 
       </select> 
      </td> 
      <td> 
       <input type=button value=Add data-bind='click: addFoodie' /> 
      </td> 
     </tr> 
    </thead> 
    <tbody data-bind='foreach: foodies'> 
     <tr> 
      <td> 
       <input type=text data-bind='value: name' /> 
      </td> 
      <td> 
       <select data-bind='value: food'> 
        <option value=apple data-bind>Apple</option> 
        <option value=banana>Banana</option> 
        <option value=cherry>Cherry</option> 
       </select> 
      </td> 
      <td> 
       <input type=button value=del data-bind='click: $parent.delFoodie' /> 
      </td> 
     </tr> 
    </tbody> 
</table> 
<input type=button value=debug data-bind='click: debug' /> 
<!-- why the following <pre> tag is empty? --> 
<pre data-bind='text: ko.toJSON(app, null, 4)'></pre> 

回答

2

这里是一个更新的小提琴:http://jsfiddle.net/jearles/TgD6a/3/

-

  • Q1:你没有初始化你foodie对象
  • Q2:app是不是你的视图模型的一部分 - 它是视图模型。使用$root访问顶级ViewModel问题3:这与您定义方式foodieToAdd的方式有关。基本上你只能创建一个实例,所以Knockout一直添加同一个对象。因为您没有可观察的属性,所以敲除没有更新UI。

在我的小提琴中,我改变了如何定义foodieToAdd。它现在只是一个标准对象,具有两个可观察的属性。当您单击add时,它会克隆foodieToAdd以在observableArray中创建一个新条目。

编辑:见下面的评论为什么淘汰赛是拾起result

-

function foodie(foodie) { 
    this.name = ko.observable(foodie ? foodie.name() : ''); 
    this.food = ko.observable(foodie ? foodie.food() : ''); 
} 

function foodieApp() { 
    var self = this; 
    self.foodies = ko.observableArray(); 
    self.foodieToAdd = new foodie(); 

    self.addFoodie = function() { 
     this.foodies.push(new foodie(this.foodieToAdd)); 
    }; 

    self.delFoodie = function (foodieToDel) { 
     self.foodies.remove(foodieToDel); 
    }; 

    self.debug = function() { 
     alert(ko.toJSON(self, null, 4)); 
    }; 
} 

var app = new foodieApp(); 
ko.applyBindings(app); 
+0

这是正确的,但我不明白,为什么'result'是越来越放在'name'结合。有任何想法吗? – 2013-04-24 23:07:06

+0

我不完全是为什么,除了它必须绑定到属性没有初始化。它看起来像是Knockout的DOM渲染逻辑中的一些东西。如果你看这个小提琴(http://jsfiddle.net/jearles/TgD6a/4/),你会看到你的调试渲染。你会在对象中看不到任何名字,但是你可以把'result'改成'res',如果你点击add,它就会获得这个值。 – 2013-04-24 23:25:58

+0

今天早上我做了一些调试,交换了knockout的调试版本。 “结果”的原因正在变得非常简单,但它涉及到一点JavaScript语句:'with'。 淘汰赛正在评估此功能: '用($上下文){用($数据|| {}){{回报 '值':姓名,...}}}' 的'with'语句添加'$ context'和'data'到它将尝试解析'name'的范围链。这两者都没有'name'属性,但'this'(这是Window)确实......并且它是'result'。尝试将'name'改为'foodieName',我们不再有意想不到的'结果'。 – 2013-04-25 11:42:13