【问题标题】:Update ViewModel in Knockout在 Knockout 中更新 ViewModel
【发布时间】:2017-10-14 10:24:01
【问题描述】:

我是 Knockout 的新手。我正在尝试使用 Knockout 开发 购物车 功能。

我的问题是当我想在我的购物车中放置一个计数器时,计数器将应用于所有购物车内容。

var FoodVM = function() {
  self.ID = ko.observable();
  self.Name = ko.observable();
  self.Price = ko.observable();
  self.Clicks = ko.observable(0);

  self.clickCounterAdd = function() {
    self.Clicks(self.Clicks() + 1);
  };
};

var FoodsListVM = function() {
  this.FoodsList = ko.observableArray([new FoodVM()]);
};

$(document).ready(function() {
  var model = new FoodsListVM();
  ko.applyBindings(model);

  var data = [{
      ID: 1,
      Name: "Test 1",
      Price: 25000
    },
    {
      ID: 2,
      Name: "Test 2",
      Price: 30000
    },
    {
      ID: 3,
      Name: "Test 3",
      Price: 35000
    }
  ];

  model.FoodsList(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<table border="1">
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Price</th>
    <th>Add</th>
    <th>Count</th>
  </tr>
  <tbody data-bind="foreach: FoodsList">
    <tr>
      <td data-bind="text: ID"></td>
      <td data-bind="text: Name"></td>
      <td data-bind="text: Price"></td>
      <td>
        <button data-bind="click: clickCounterAdd" style="width: 73px;">Add</button>
      </td>
      <td>
        <input type="text" data-bind="value: Clicks" style="width: 20px;">
      </td>
    </tr>
</table>

JSFiddle 演示。

你能告诉我我的错误在哪里吗?

【问题讨论】:

    标签: knockout.js viewmodel


    【解决方案1】:

    您的第一个错误是忘记在您的FoodVM 中定义self

    var self = this;
    

    因此,您将所有可观察对象和 clickCounterAdd 函数附加到恰好在全局范围内的任何 self,而不是您的视图模型。

    下一个错误是您使用单个 FoodVM 初始化 FoodsList 属性...

    this.FoodsList = ko.observableArray([new FoodVM()]);
    

    ...但是片刻之后,您会用一个简单的 JS 对象 data 覆盖它。

    model.FoodsList(data);
    

    这意味着FoodVM 丢失了-data 中的项目不会自行变为FoodVMs。需要某种循环来将数据数组中的普通对象转换为FoodVM 实例。通常这是通过.map() 调用来完成的。


    这是构建视图模型的更好方法。

    以这样一种方式编写您的视图模型,即它们从参数对象(即从模型)初始化自己。使数据的属性名称与视图模型的属性名称匹配。

    function someViewmodel(params) {
        this.data = ko.observable(params.data);
    }
    

    在您的情况下,有两个视图模型,FoodFoodsList(我觉得称它们为 *VM 是多余的,所以我不这样做)。我已向模型 (foods) 添加了一层以匹配 FoodsList 中的同名属性。

    var Food = function(params) {
      var self = this;
      
      self.ID = ko.observable(params.ID);
      self.Name = ko.observable(params.Name);
      self.Price = ko.observable(params.Price);
    
      self.clicks = ko.observable(0);
      self.countClick = function () {
        self.clicks(self.clicks() + 1);
      };
    };
    
    var FoodsList = function(params) {
      var self = this; 
    
      self.foods = ko.observableArray(params.foods.map(function (item) {
        return new Food(item);
      }));
    };
    
    
    // ----------------------------------------------------------------------
    var model = {
      foods: [
        { ID: 1, Name: "Test 1", Price: 25000 },
        { ID: 2, Name: "Test 2", Price: 30000 },
        { ID: 3, Name: "Test 3", Price: 35000 }
      ]
    };
    
    var vm = new FoodsList(model);
    ko.applyBindings(vm);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <table border="1">
      <tr>
        <th>ID</th>
        <th>Name</th>
        <th>Price</th>
        <th>Add</th>
        <th>Count</th>
      </tr>
      <tbody data-bind="foreach: foods">
        <tr>
          <td data-bind="text: ID"></td>
          <td data-bind="text: Name"></td>
          <td data-bind="text: Price"></td>
          <td>
            <button data-bind="click: countClick" style="width: 73px;">Add</button>
          </td>
          <td>
            <input type="text" data-bind="value: clicks" style="width: 20px;">
          </td>
        </tr>
    </table>

    注意在初始化期间一切都是如何自举的,new FoodsList(model) 构建了一个完整的嵌套视图模型。

    顺便说一句,这个任务很常见,有一个淘汰插件可以为您完成:http://knockoutjs.com/documentation/plugins-mapping.html。花点时间阅读它的文档。

    【讨论】:

      【解决方案2】:

      看看下面的变化

      var Food = function(params) {
        var self = this;
      
        self.ID = ko.observable(params.ID);
        self.Name = ko.observable(params.Name);
        self.Price = ko.observable(params.Price);
      
        self.clicks = ko.observable(0);
        self.countClick = function () {
          self.clicks(self.clicks() + 1);
        };
      };
      
      var FoodsList = function(params) {
        var self = this; 
      
        self.foods = ko.observableArray(params.foods.map(function (item) {
          return new Food(item);
        }));
      };
      
      
      // ----------------------------------------------------------------------
      var model = {
        foods: [
          { ID: 1, Name: "Test 1", Price: 25000 },
          { ID: 2, Name: "Test 2", Price: 30000 },
          { ID: 3, Name: "Test 3", Price: 35000 }
        ]
      };
      
      var vm = new FoodsList(model);
      ko.applyBindings(vm);
      

      【讨论】:

        猜你喜欢
        • 2012-08-28
        • 1970-01-01
        • 2013-01-10
        • 2014-05-05
        • 2014-09-23
        • 2015-01-17
        • 2012-02-29
        • 2014-10-05
        • 2014-06-07
        相关资源
        最近更新 更多