Knockout.Js案例二Working With Lists And Collections

案例一:Foreach绑定html

一般,您要生成重复的UI元素,特别是当显示列表,用户能够添加和删除元素。KO.JS让你轻松,使用的数组和foreach绑定。数组

 

在接下来的几分钟,您将构建一个动态UI保留席位和吃饭——这多是一个一步一个机票预订过程。在右下方的窗格中,您已经有了:服务器

HTML:app

 <h2>Your seat reservations</h2>框架

< table >
     < thead > < tr >
         < th > Passenger name </ th > < th > Meal </ th > < th > Surcharge </ th > < th > </ th >
     </ tr > </ thead >
     <!-- Todo: Generate table body -->
    < tbody  data-bind = "foreach: seats" >
     < tr >
         < td  data-bind = "text: name" > </ td >
         < td  data-bind = "text: meal().mealName" > </ td >
         < td  data-bind = "text: meal().price" > </ td >

    </tr>编辑器

   </tbody>函数

</table>学习

 

JS:ui

 function SeatReservation(nameinitialMeal{this

     var  self  this ;
     self . name  name ;
     self . meal  ko . observable ( initialMeal ) ;
}

SeatReservation,一个简单的JS的数,选择存储乘客名字和一顿饭

 function ReservationsViewModel({

     var  self  this ;

     // Non-editable catalog data - would come from the server
     self . availableMeals  [
         mealName "Standard (sandwich)" price } ,
         mealName "Premium (lobster)" price 34.95  } ,
         mealName "Ultimate (whole zebra)" price 290  }
     ] ;    

     // Editable data
     self . seats  ko . observableArray ( [
         new  SeatReservation ( "Steve" self . availableMeals [ 0 ] ) ,
         new  SeatReservation ( "Bert" self . availableMeals [ 0 ] )
     ] ) ;
}

ko.applyBindings(new ReservationsViewModel());

 

ReservationsViewModel:viewmodel类:

availableMeals: js对象提供餐数据,

seat:数组初始SeatReservation实例的集合。

请注意,这是一个observableArray——绝不奇怪,可见至关于一个常规数组中,这意味着它能够自动触发更新UI项添加或删除。


Notice that, because the meal property is an observable, it's important to invoke meal()as a function (to obtain its current value) before attempting to read sub-properties. In other words, write meal().pricenot meal.price.

请注意,由于这顿饭属性是一个可观察到的,是很重要的()做为一个函数来调用餐(得到其当前值)以前sub-properties阅读。换句话说,写餐()。的价格,而不是meal.price。由于字段是能够观察到的,是很重要的,因此须要();

 

foreach is part of a family of control flow bindings that includes foreachififnot, and with. These make it possible to construct any kind of iterative, conditional, or nested UI based on your dynamic viewmodel.

foreach属于控制流绑定的一部分。这让咱们构造任何类型的迭代,条件,或嵌套的基于动态viewmodel的UI

 

 

 案例2:Add Item新增项

 MVVM模式后使它很是简单的使用数组和层次等多变的对象图。你更新基础数据,UI自动更新同步。


实现增长座位预订:

添加一个按钮到视图,使用点击绑定关联与函数在你点击视图模型:

 <button data-bind="click: addSeat">Reserve another seat</button>

而后实现addSeat函数,使其推进额外进入座位数组:

 

function ReservationsViewModel() {
     var self =  this;

     //  Non-editable catalog data - would come from the server
    self.availableMeals = [
        { mealName: "Standard (sandwich)", price: 0 },
        { mealName: "Premium (lobster)", price: 34.95 },
        { mealName: "Ultimate (whole zebra)", price: 290 }
    ];    

     //  Editable data
    self.seats = ko.observableArray([
         new SeatReservation("Steve", self.availableMeals[0]),
         new SeatReservation("Bert", self.availableMeals[0])
    ]);
     self.addSeat =  function() {
        self.seats.push( new SeatReservation("", self.availableMeals[0]));
    }

} 

 试一试,如今当你点击“预订另外一个座位”,UI更新以匹配。这是由于座位是可观察到的数组,因此添加或删除条目将自动触发更新UI。

 注意,添加一行不涉及再生整个UI。为了提升效率,KO.JS跟踪改变在你的视图模型,并执行DOM更新以匹配的最小集合。这意味着您能够扩大规模很是大或复杂的ui,甚至它能够保持时髦和响应在低端移动设备.

 

 

案例三:使数据能够编辑

你可使用绑定在foreach块和其余地方同样,因此很容易升级咱们进入一个完整的数据编辑器。更新您须要的东西:

 <tbody data-bind="foreach: seats">

    <tr>
        <td><input data-bind="value: name" /></td>
        <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
        <td data-bind="text: meal().price"></td>
    </tr>    
</tbody>  
这段代码使用了两个新的绑定,选项和optionsText,一块儿控制两组可用的项目在一个下拉列表,和对象属性(在本例中,mealName)是用来表示屏幕上的每一项

 如今试一试,你能够选择从可用的饭菜,和这样作会致使相应的行(只)刷新显示,饭菜的价格。

 

格式化Prices


 咱们有一个不错的面向对象的表示咱们的数据,因此咱们能够平凡地添加额外的属性和函数对象图的任何地方。让咱们给SeatReservation类格式的能力本身的价格数据使用一些自定义的逻辑。

   1function SeatReservation(name, initialMeal) {

 2      var self =  this;
 3     self.name = name;
 4     self.meal = ko.observable(initialMeal);
 5 
 6     self.formattedPrice = ko.computed( function() {
 7          var price = self.meal().price;
 8          return price ? "$" + price.toFixed(2) : "None";        
 9     });
10 }  
如今你能够更新视图使用了formattedPrice每一个SeatReservation实例:  

 

因为格式化的价格将计算基于所选餐,咱们可使用ko.computed表明(所以它将自动更新时餐选择更改):
function SeatReservation(name, initialMeal) {
     var self =  this;
    self.name = name;
    self.meal = ko.observable(initialMeal);

    self.formattedPrice = ko.computed( function() {
         var price = self.meal().price;
         return price ? "$" + price.toFixed(2) : "None";        
    });
}

 如今你能够更新视图使用了formattedPrice每一个SeatReservation实例:

1 <tr>
2     <td><input data-bind="value: name" /></td>
3     <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
4     <td data-bind="text: formattedPrice"></td>

5 </tr> 

 

 案例四:删除项目和总和

 由于你能够添加条目,您应该可以删除它们,对吗?如您所料,这只是一个更新底层数据的问题。      

更新你的视图,它显示每一个条目旁边的“删除”连接

<tr>
    <td><input data-bind="value: name" /></td>
    <td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
    <td data-bind="text: formattedPrice"></td>
    <td><a href="#" data-bind="click: $root.removeSeat">Remove</a></td>

</tr>       

注意,$ root。前缀致使KO.JS寻找removeSeaf方法在你的顶层视图模型而不是SeatReservation实例绑定——这是一个更方便的地方把removeSeat这个例子。

所以,添加相应的removeSeat函数根viewmodel类,ReservationsViewModel:

 1 function ReservationsViewModel() {

2      //  ... leave the rest unchanged ...
3 
4      //  Operations
5      self.addSeat =  function() {  /*  ... leave unchanged ...  */ }
6     self.removeSeat =  function(seat) { self.seats.remove(seat) }
7 }   

 如今,若是你运行应用程序时,您将可以删除物品以及添加它们。

 

显示一个总附加费:
最好是让客户知道他们要支付,对吗?绝不奇怪,咱们能够定义为一个计算的属性,让框架照顾知道何时从新计算并刷新显示。      

添加如下ko.computed ReservationsViewModel内:

 

1 self.totalSurcharge = ko.computed( function() {
2     var total = 0;
3     for ( var i = 0; i < self.seats().length; i++)
4        total += self.seats()[i].meal().price;
5     return total;
6 });


再次注意,由于座椅和饭均可见,咱们调用函数来读他们的当前值(例如self.seats(). length)。

显示所有附加费经过添加如下< h3 >元素

 <h3 data-bind="visible: totalSurcharge() > 0">

    Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</h3>

这段代码演示了两个点:      

可见绑定使有形或无形的元素做为数据更改(在内部,它修改元素的CSS显示样式)。在本例中,咱们选择只显示“总附加费”信息若是是大于零。   

您可使用任意JavaScript表达式内部声明式绑定。在这里,咱们使用totalSurcharge()> 0和totalSurcharge().toFixed(2)。在内部,这实际上定义了一个属性来表示的输出,计算表达式。它只是一个很是轻量级的和方便的语法的选择。

 

如今,若是你运行代码,您将看到“总附加费”出现和消失,因为依赖跟踪,它知道何时从新计算本身的价值——你不须要任何代码在你的“增长”或“删除”功能,迫使依赖手动更新。

 

最后的细节:

随着MVVM模式,UI的一个面向对象的表示的数据和行为,你在一个好位置洒在额外的行为在一个很是天然和方便的方式。

例如,若是你要求显示的总数预留座位,您能够实如今一个地方,你不须要写任何额外代码以使座位数量更新当你添加或删除条目。只是更新< h2 >顶部的观点:

1 <h2>Your seat reservations (<span data-bind="text: seats().length"></span>)</h2> 

 

一样,若是你要求限制数量的席位能够储备,说,可使UI表示,经过使用使绑定:

按钮时座位限制成了残疾。你没必要编写任何代码从新启用它,当用户删除一些席位(搞乱你的“删除”逻辑),由于表达式将自动从新评估相关数据变化时所击倒。

 

最后:若是你想学习的方法保存回服务器更新数据,看教程的加载和保存数据。

相关文章
相关标签/搜索