2013-06-05 21 views
0

我学习使用MVC 4/MVVM /淘汰赛的网络管理数据项目更新。在可观察数组上使用remove函数时,我遇到了更新View的问题。使用推送或不移位时会发生更新,但不会移除。在chrome中使用调试器,我可以看到数据正在从数组中删除,更新事件不起作用。从HTML视图无法在淘汰赛observablearray.remove(项目),而不调用applyBindings

片断如下表,有我没包括添加或编辑数据的表单。

<div id="MessageDiv" data-bind="message: Message"></div> 
<div class="tableContainer hiddenHead"> 
    <div class="headerBackground"></div> 
    <div class="tableContainerInner"> 
     <table id="adapter-table" class="grid" data-bind="sortTable: true"> 
      <thead> 
       <tr> 
        <th class="first"> 
         <span class="th-inner">Name</span> 
        </th> 
        <th> 
         <span class="th-inner">DeviceID</span> 
        </th> 
        <th> 
         <span class="th-inner"></span> 
        </th> 
        <th> 
         <span class="th-inner"></span> 
        </th> 
       </tr> 
      </thead> 
      <tbody data-bind="template: { name: 'AdaptersTemplate', foreach: Adapters }"> 
      </tbody> 
     </table> 
     <script id="AdaptersTemplate" type="text/html"> 
      <tr> 
       <td data-bind="text: Name"></td> 
       <td data-bind="text: DeviceID"></td> 
       <td><a href="#" data-bind="click: $parent.selectItem">Edit</a> 
       <td><a href="#" data-bind="click: $parent.deleteItem">Delete</a> 
      </tr> 
     </script> 
    </div> 
    <input type="button" data-bind='click: addAdapter' value="Add New Adapter" /> 
    <input type="button" data-bind='click: saveAll' value="Save Changes" id="SaveChangesButton" /> 
</div> 

我的JavaScript已设置为管理VM作为restful并缓存更改。添加,编辑和保存/删除数据都似乎工作,而不会抛出我在Chrome中的调试器中看到的错误。确认更改似乎可以正常工作,并按预期对数据库进行更改。

$(function() { 
    var viewModel = new AdaptersModel(); 
    getData(viewModel); 
}); 

function getData(viewModel) { 
    $.getJSON("/api/AdapterList", 
    function (data) { 
     if (data && data.length > 0) { 
      viewModel.SetAdaptersFromJSON(data); 
     } 
     ko.applyBindings(viewModel); 
    }); 
} 

//#region AdapterVM 
function Adapter(name, siFamily, deviceIDs) { 
    var self = this; 
    self.Name = ko.observable(name); 
    self.DeviceID = ko.observable(deviceIDs); 
    self.ID = 0; 
} 

function AdaptersModel() { 
    var self = this; 

    self.Adapters = ko.observableArray([]); 
    self.DeleteAdapters = ko.observableArray([]); 
    self.NewAdapter = ko.observable(new Adapter("", "", "", "")); 

    self.Message = ko.observable(""); 

    self.SetAdaptersFromJSON = function (jsData) { 
     self.Adapters = ko.mapping.fromJS(jsData); 
    }; 

    //#region Edit List Options: confirmChanges 
    self.confirmChanges = function() { 
     if (self.NewAdapter().ID == 0) { 
      self.Adapters.push(self.NewAdapter()); 
     } 
    }; 
    //#endregion 

    //#region Adapter List Options: addAdapter, selectItem, deleteItem, saveAll 
    self.addAdapter = function() { 
     self.NewAdapter(new Adapter("", "", "", "")); 
    }; 

    self.selectItem = function (item) { 
     self.NewAdapter(item); 
    }; 

    self.deleteItem = function(item) { 
     self.DeleteAdapters.push(item.ID()); 
     self.Adapters.remove(item); 
    }; 

    self.saveAll = function() { 
     if (self.Adapters && self.Adapters().length > 0) { 
      var filtered = ko.utils.arrayFilter(self.Adapters(), 
       function(adapter) { 
        return ((!isEmpty(adapter.Manufacturer())) && 
         (!isEmpty(adapter.Name())) && 
         (!isEmpty(adapter.DeviceIDs())) 
        ); 
       } 
      ); 

      var updateSuccess = true; 
      if (self.DeleteAdapters().length > 0) { 
       jsonData = ko.toJSON(self.DeleteAdapters()); 
       $.ajax({ 
        url: "/api/AdapterList", 
        cache: false, 
        type: "DELETE", 
        data: jsonData, 
        dataType: "json", 
        contentType: "application/json; charset=utf-8", 
        success: function() { updateSuccess = true; }, 
        error: function() { updateSuccess = false; } 
       }); 
      } 

      var jsonData = ko.toJSON(filtered); 
      $.ajax({ 
       url: "/api/AdapterList", 
       type: "POST", 
       data: jsonData, 
       dataType: "json", 
       contentType: "application/json; charset=utf-8", 
       success: function(data) { 
        self.SetAdaptersFromJSON(data); 
        updateSuccess = true && updateSuccess; 
       }, 
       error: function() { updateSuccess = false; } 
      }); 

      if (updateSuccess == true) { self.Message("Update Successfull"); } 
      else { self.Message("Update Failed"); } 
     } 
    }; 
    //#endregion 
} 
//#endregion 

ko.bindingHandlers.message = { 
    update: function(element, valueAccessor) { 
     $(element).hide(); 
     ko.bindingHandlers.text.update(element, valueAccessor); 
     $(element).fadeIn(); 
     $(element).fadeOut(4000); 
    } 
}; 

ko.bindingHandlers.sortTable = { 
    init: function (element, valueAccessor) { 
     setTimeout(function() { 
      $(element).addClass('tablesorter'); 
      $(element).tablesorter({ widgets: ['zebra'] }); 
     }, 0); 
    } 
}; 

function isEmpty(obj) { 
    if (typeof obj == 'undefined' || obj === null || obj === '') return true; 
    if (typeof obj == 'number' && isNaN(obj)) return true; 
    if (obj instanceof Date && isNaN(Number(obj))) return true; 
    return false; 
} 

未能成功地更新我的html表,具体脚本部分是:

self.deleteItem = function(item) { 
    self.DeleteAdapters.push(item.ID()); 
    self.Adapters.remove(item); 
}; 

一切似乎除了删除工作,所以我似乎是在为看什么损失接下来,我太新了JavaScript或淘汰赛知道这是否是一个线索:如果我在self.deleteItem函数中运行ko.applyBindings()命令,我得到更新发生,但它确实给我一个未处理的错误:

Uncaught Error: Unable to parse bindings. Message: ReferenceError: Message is not defined; Bindings value: message: Message

消息在绑定之前在虚拟机中定义...是否有我在所有这些中错过的东西?

+1

您可以加入到你的问题,它使用您的自定义消息绑定的HTML? – RodneyTrotter

回答

1

有很多帮助解决周围的问题,但没有真正解决问题的“原因”。更新有时可以完美运行,但不是其他时间。当我对它进行故障排除并开始弄虚作假并在JSFiddle中工作时,我没有在我的所有工作版本中包含data-bind="sortTable: true"。显然,如果你按照我的方式对表格或代码进行排序,它将无法工作。该示例代码中,我所看到的漂浮是在这里http://jsfiddle.net/gregmason/UChLF/16/,相关代码:

ko.bindingHandlers.tableSorter = { 
    init: function (element) { 
     setTimeout(function() { $(element).tablesorter(); }, 0); 
    }, 
    update: function (element, valueAccessor) { 
     ko.utils.unwrapObservable(valueAccessor()); //just to get a dependency 
     $(element).trigger("update"); 
    } 
}; 

的错误行为可以通过点击该行的删除链接是显而易见的。

  • 如果您单击没有排序的行,您将看到该行消失正确。
  • 如果您首先点击一列以不同的顺序重新排序,那么删除该行,它将保留在表中并显示为已缓存。 knockout js - Table sorting using column headers

这可以通过结合各表头,而不是表本身,并用作为在这个线程讨论的自定义行为sort更换tableSorter代码来处理。排序更换是在这里:

ko.bindingHandlers.sort = { 
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var asc = false; 
     element.style.cursor = 'pointer'; 

     element.onclick = function(){ 
      var value = valueAccessor(); 
      var prop = value.prop; 
      var data = value.arr; 

      asc = !asc; 
      if(asc){ 
       data.sort(function(left, right){ 
        return left[prop]() == right[prop]() ? 0 : left[prop]() < right[prop]() ? -1 : 1; 
       }); 
      } else { 
       data.sort(function(left, right){ 
        return left[prop]() == right[prop]() ? 0 : left[prop]() > right[prop]() ? -1 : 1; 
       }); 
      } 
     } 
    } 
}; 

这已固定我的排序/编辑/删除问题和工作的jsfiddle是在这里:http://jsfiddle.net/gregmason/UChLF/18/

1

在你的js的文件开头要定义VAR视图模型=新AdaptersModel();但较低,你说的函数Adapter()是你的区域声明中的视图模型。它使你的代码难以阅读。我将再次尝试解决您的问题,但我建议您的viewmodel包含适配器,并且您的模型包含每个适配器应该是什么类的类实例。

你所得到的特定错误是因为你绑定消息()的东西,然后删除留言()。有一两件事你可以做麻烦拍摄这是您的div更改为类似:

<div id="MessageDiv" data-bind="with: Message"> 
    <h5 data-bind="message: $data"><h5> 
</div> 

如果你可以创建一个小提琴,我可以给出一个更明确的例子,为什么,但基本上如果消息()是空白使用绑定不应显示删除后未定义的标头。

什么,你可能需要做虽然是看什么来发送的“项目”,并确保它是不是你的视图模型。

self.deleteItem = function(item) { 
     console.log(item); // << Check console and see what is being returned 
     self.DeleteAdapters.push(item.ID()); 
     self.Adapters.remove(item); 
    }; 

您可能删除的不仅仅是一个适配器。

这将引导你正确的方向,但我会认真考虑重新命名你的代码。

+0

缺少模板?我用来编辑或添加新适配器的唯一“形式”......如果我能弄清楚如何在jsfiddle中复制所有内容,我将尽快链接。 –

+0

没关系,你编辑过,包括你使用绑定处理程序的地方,让我们来看看它。 –

+1

我调整了我的答案,给你一个更好的方向。让我知道这是如何工作的,如果你得到了一个小提示并运行 –