使用knockoutjs将节点动态添加到列表中

时间:2016-02-27 21:29:12

标签: knockout.js

我有一个嵌套的HTML列表,当我点击展开一个节点时,我需要动态加载新项目。我找到并修改了this snippet但是当我尝试在列表中推送新节点时出现错误:

<!DOCTYPE html>
<html>

<head>
  <link data-require="font-awesome@*" data-semver="3.0.2" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/3.0.2/css/font-awesome.min.css" />
  <script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
  <script data-require="knockout@*" data-semver="2.3.0" src="http://knockoutjs.com/downloads/knockout-2.3.0.js"></script>
  <script data-require="knockout.mapping@*" data-semver="2.3.5" src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.3.5/knockout.mapping.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
  <script type="text/html" id="tree-node">
    <li>
      <span class="node-toggle" data-bind="visible: expanded, click: toggle">&ndash;</span>
      <span class="node-toggle" data-bind="visible: collapsed, click: toggle">+</span>
      <span class="node-label" data-bind="text: name, click: $root.selected"></span>

      <div data-bind="if: expanded">
        <ul data-bind="template: {name: 'tree-node', foreach: children}"></ul>
      </div>
    </li>
  </script>
</head>

<body>
  <h1>Example Tree</h1>
  <p>Click on the plus sign to expand a node, click on the label to select it.</p>
  <ul data-bind="template: {name: 'tree-node', data: root}"></ul>
  <div data-bind="if: selected">
    <div data-bind="with: selected">
      Selected Node: <span data-bind="text: name"></span>
    </div>
  </div>
</body>

</html>

HTML

// Code goes here
$(function() {
  function TreeNode(values) {
      var self = this;
      ko.mapping.fromJS(values, { children: { create: createNode }}, this);
      this.expanded = ko.observable(false);
      this.collapsed = ko.computed(function() {
      return !self.expanded();
    })
  }



  TreeNode.prototype.toggle = function () {
      this.expanded(!this.expanded());
      if (this.expanded() && !this.children().length){
        // This throw an error
        this.children.push(TreeNode(
          {id: "xxxx", name: "Node xxxx", children: []}
          ));
      } 
  };

  function createNode(options) {
      return new TreeNode(options.data);
  }

  var root = new TreeNode({ id: "1", name: "Root", children: [
      { id: "1.1", name: "Node 1", children: [
          {id: "1.1.1", name: "Node 1.1", children: []},
          {id: "1.1.2", name: "Node 1.2", children: []}
      ]},
      { id: "1.2", name: "Node 2", children: []}
  ]});

  var viewModel = {
      root: root,
      selected: ko.observable()
  };

  ko.applyBindings(viewModel, $('html')[0]);
});

JS

/* Styles go here */

ul, li {
  list-style: none;
}

.node-label {
  cursor: pointer;
}
.node-toggle {
  display: inline-block;
  width: 1em;
  cursor: pointer;
}

CSS

{{1}}

理想情况下,解决方案应该适用于无限的嵌套级别。任何人都可以给我一个提示吗?

1 个答案:

答案 0 :(得分:1)

TreeNode是一个构造函数,但是你在行中没有new的情况下调用它

this.children.push(TreeNode(
  {id: "xxxx", name: "Node xxxx", children: []}
  ));

这只是你必须注意的其中一个问题。如果您使用strict mode,则在未使用this调用的构造函数中使用new将是undefined而不是全局对象。这可能有所帮助。