当我尝试从中删除一个项目时,如果它有多个项目,则Knockout,collection属性变为null?

时间:2016-11-14 22:29:13

标签: javascript jquery knockout.js knockout-mapping-plugin

我有非常奇怪的淘汰赛错误。这是一个非常复杂的场景所以请看这个小提琴:

http://jsfiddle.net/yx8dkLnc/

基本上我有一个双嵌套集合,第一个集合FishMeasurements包含一系列具有与之关联的物种信息的对象,以及一个Measurements集合,其中包含与该物种相关的所有测量值

现在,当我尝试从此HTML中的嵌套集合中删除项目时:

<!-- ko foreach: FishMeasurements() -->
                <h3><span data-bind="text: SpeciesName"></span><span data-bind="text: SpeciesId" style="display: none;"></span></h3>
                <table class="table table-striped">
                    <thead>
                        <tr>
                            <th>Length</th>
                            <th>Count</th>
                            <th>Weight</th>
                            <th>Fish Id</th>
                            <th>&nbsp;</th>
                        </tr>
                    </thead>
                    <tbody data-bind="foreach: Measurements()">
                        <tr>
                            <td><span data-bind="text: LengthInMillimeters"></span></td>
                            <td><span data-bind="text: Count"></span></td>
                            <td><span data-bind="text: WeightInPounds"></span></td>
                            <td><span data-bind="text: FishCode"></span></td>
                            <td><a href="#" data-bind="click: function() { $root.removeMeasurement($data, $index); }">Remove</a></td>
                        </tr>
                    </tbody>
                </table>
            <!-- /ko -->

Measurements集合有多个对象时,删除测量功能不起作用。我单击删除链接,它会抛出一个错误:

  

VM617:163未捕获的TypeError:无法读取属性&#39;测量&#39; of null(...)

这个奇怪的是,如果我只在Measurements集合中添加一个项目,删除按钮工作正常,但是一旦我添加多个测量,如果我在表格中的任何项目上单击删除但第一行,生成此错误。但是,如果我单击每个物种的表格中的第一项,则没有错误,并且所有记录都被删除了!

Something告诉我它将Measurements视为一个对象而不是集合,因为它仅适用于索引0.但我不确定,因为在控制台中我可以输入:

mappedModel.FishMeasurements()[0].Measurements()[1]

并返回一个完整的ko_mapping对象,因此它不为空。但由于某些原因,当我单击删除时,它为空。只要每个物种只有一个测量值,单击删除就可以正常工作,只要它有更多的断裂。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

首次addMeasurement speciesId时,speciesNamefishMeasurementBySpecies === undefined而被定义,因此当您删除第一项时,您有measurement.SpeciesId() }作为removeMeasurement函数内的参数,但是第二次以及更多,因为fishMeasurementBySpecies不再是undefinedspeciesIdspeciesName永远不会被设置,然后当调用removeMeasurementmeasurement.SpeciesId()为空。

为了使您的模型有效,您需要应用以下更改。

在if语句

之前定义var speciesId = mappedModel.SelectedSpecies();
var speciesId = mappedModel.SelectedSpecies();
if (fishMeasurementBySpecies === undefined || fishMeasurementBySpecies === null) {

()放入removeMeasurement函数中的Measurements,以获取长度

if(fishMeasurementBySpecies.Measurements().length === 0) 

下面我将为您提供一个使用手动视图模型而不是使用mapping插件的示例。

示例:https://jsfiddle.net/kyr6w2x3/118/

您的示例:http://jsfiddle.net/yx8dkLnc/1/

VM:

var data = {
    "AvailableSpecies":
            [
            {"Id":"f57830b8-0766-4374-b481-82c04087415e","Name":"Alabama Shad"},    
          {"Id":"3787ce10-e61c-4f03-88a5-ff648bb55480","Name":"Alewife"},{"Id":"e923214f-4974-4663-9158-d6979ce637f1","Name":"All Sunfish Spp Ex Bass And Crappie"}          ],
        "SelectedSpecies": null,  "CountToAdd":0,"LengthToAdd":0,"WeightToAdd":0,"GenerateFishCode":false,"FishMeasurements":[]
};
function AppViewModel(){
   var self = this;
   self.AvailableSpecies = ko.observableArray(data.AvailableSpecies);
   self.SelectedSpecies = ko.observable();
   self.CountToAdd = ko.observable();
   self.LengthToAdd = ko.observable();
   self.WeightToAdd = ko.observable();
   self.FishCode = ko.observable();
   self.FishMeasurements = ko.observableArray([]);

   self.addMeasurement = function(item) {
     var SpeciesExists = false;

     ko.utils.arrayForEach(self.FishMeasurements(), function (item) {
       if(item.SpeciesId() == self.SelectedSpecies().Id) {
         var len = item.Measurements().length;
         // you may have a better way to generate a unique Id if an item is removed 
         while(item.Measurements().findIndex(x => x.Id() === len) > 0){
            len++;
         }
         item.Measurements.push(new MeasurementsViewModel({LengthInMillimeters:self.LengthToAdd(),
                                                           Count:self.CountToAdd(),
                                                           WeightInPounds:self.WeightToAdd(),
                                                           FishCode:self.FishCode(),
                                                           Id:len ++,
                                                           ParentId:self.SelectedSpecies().Id
                                                          })
                               );
         SpeciesExists = true;
       }
     });
     if(!SpeciesExists){
       self.FishMeasurements.push(new FishMeasurementsViewModel({SpeciesName:self.SelectedSpecies().Name,
                                                                 SpeciesId:self.SelectedSpecies().Id,
                                                                 Measurements:[{LengthInMillimeters:self.LengthToAdd(),
                                                                                Count:self.CountToAdd(),
                                                                                WeightInPounds:self.WeightToAdd(),
                                                                                FishCode:self.FishCode(),
                                                                                Id:1}]
                                                                })
                                 );
     }
   }
   self.removeMeasurement = function(data){
       ko.utils.arrayForEach(self.FishMeasurements(), function (item) {
            if(item && item.SpeciesId() == data.ParentId()) {
            ko.utils.arrayForEach(item.Measurements(), function (subItem) {
              if(subItem && subItem.Id() == data.Id()) {
                                item.Measurements.remove(subItem);
              }
            });
          }
          if(item && item.Measurements().length == 0){
             self.FishMeasurements.remove(item);
          }
       });
   }
 }
  var FishMeasurementsViewModel = function(data){
   var self = this;
   self.SpeciesName = ko.observable(data.SpeciesName);
   self.SpeciesId = ko.observable(data.SpeciesId);
   self.Measurements = ko.observableArray($.map(data.Measurements, function (item) {
     return new MeasurementsViewModel(item,self.SpeciesId());
   }));

 }
 var MeasurementsViewModel = function(data,parentId){
   var self = this;
   self.LengthInMillimeters = ko.observable(data.LengthInMillimeters);
   self.Count = ko.observable(data.Count);
   self.WeightInPounds = ko.observable(data.WeightInPounds);
   self.FishCode = ko.observable(data.FishCode);
   self.Id = ko.observable(data.Id);
   self.ParentId = ko.observable(parentId ? parentId : data.ParentId);
 }

var viewModel = new AppViewModel();
ko.applyBindings(viewModel);