您不能将多个绑定应用于同一个元素

时间:2017-01-03 06:49:04

标签: knockout.js

我正在使用 knockoutjs MVC5 来显示员工的职位列表。根据员工角色列表应该改变。我第一次选择角色时一切正常,但是当我改变角色然后获得

错误

  

"您不能将多个绑定应用于同一个元素。"

我试图了解这个和解决方案背后的原因,然后得到一个我们需要使用ko.cleanNode(document.getElementById(" abc"))的解决方案;但它没有用。

代码

var initialData = [{
  availableItems: data.availableItems
}, {
  selectedItems: data.selectedItems
}];

function Item(titleText, userId, isSelected) {
  this.title = ko.observable(titleText);
  this.isSelected = ko.observable(isSelected);
  this.userId = ko.observable(userId);
}

var SelectableItemViewModel = function(items) {
  var self = this;
  self.filter = ko.observable("");
  self.availableItems = ko.observableArray(ko.utils.arrayMap(items[0].availableItems, function(item) {
    return new Item(item.UserName, item.UserId, item.Status);
  }));

  self.selectedItems = ko.observableArray(ko.utils.arrayMap(items[1].selectedItems, function(item) {
    return ko.utils.arrayFirst(self.availableItems(), function(itm) {
      return item.UserName == itm.title();
    });

  }));


  self.filteredItems = ko.dependentObservable(function() {
    debugger;
    var filter = this.filter().toLowerCase();
    if (!filter) {
      return this.availableItems();
    } else {
      return ko.utils.arrayFilter(this.availableItems(), function(item) {

        return item.title().toLowerCase().indexOf(filter) !== -1;
      });
    }
    alert(this.availableItems());
  }, self);

  // Operations

  self.removeItem = function(removedItem) {
    self.selectedItems.remove(removedItem);
  };
}

var vm = new SelectableItemViewModel(initialData);
ko.applyBindings(vm);

Ajax调用

$.ajax({
                    type: 'GET',
                    url: "@Url.Action("GetAllUsersByRoleInUtility", "Home")",
                    data: { utilityId: currentUtilityId, roleId: currentRoleId },
                    dataType: 'json',
                    success: function (data) {
                        initialData[0].availableItems = data.availableItems;
                        initialData[1].selectedItems = data.selectedItems;
                        vm = new SelectableItemViewModel(initialData)

                    },
                    error: function (data) {
                        alert('Oops! something went wrong.');
                    }
                });

我第一次使用 knockoutjs

请帮助解决此问题。

1 个答案:

答案 0 :(得分:0)

当您通过ajax加载数据时,您需要决定如何更新UI后面的代码。一个重要的决定:

  1. 使用新数据创建新的视图模型
  2. 重复使用相同的视图模型,更新其中的数据或
  3. 选项1

    这是你正在尝试做的事情,而你几乎成功了。如果要在成功回调中创建新的视图模型,则必须确保将其包装在可观察的内容中。

    与您的情况相关的(简化)示例:

    
    
    // Construct the initial, empty UI
    ko.applyBindings(new App());
    
    
    function App() {
      this.selectableListVM = ko.observable(new SelectableList([]));
      
      // Later (using ajax), swap out the vm
      setTimeout(function() {
        this.selectableListVM(new SelectableList([1,2,3]));
      }.bind(this), 3000);
    
    };
    
    function SelectableList(items) {
      this.items = ko.observableArray(items);
    };
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <div data-bind="with: selectableListVM">
      <span data-bind="visible: !items().length">loading..</span>
      <ul data-bind="foreach: items">
        <li data-bind="text: $data"></li>
      </ul>
    </div>
    &#13;
    &#13;
    &#13;

    选项2

    选项2有点难以实现,但可以更高效。您需要清楚地定义数据,模型和状态之间的边界。例如,可选项目可能不会更改,而选择执行。 E.g:

    &#13;
    &#13;
    // Construct the initial, empty UI
    
    var SelectableList = function() {
      this.items = ko.observableArray([]);
      
      // This is automatically updated when you update items via ajax
      this.selectedItems = ko.pureComputed(function() {
        return this.items().filter(function(item) {
          return item.selected;
        })
      }, this);
      
    };
    
    SelectableList.prototype.loadItems = function() {
      // timeout to mock ajax
      setTimeout(function() {
        this.items([
          { name: 1, selected: Math.random() > 0.5 },
          { name: 2, selected: Math.random() > 0.5 },
          { name: 3, selected: Math.random() > 0.5 },
        ]);
      }.bind(this), 200);
    }
          
    ko.applyBindings(new SelectableList());
    &#13;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <ul data-bind="foreach: selectedItems">
      <li data-bind="text: name"></li>
    </ul>
    <button data-bind="click: loadItems">Load new state</button>
    &#13;
    &#13;
    &#13;