如何使用“with”使用嵌套的View Models在Knockout JS中绑定? [英] How to use "with" binding in Knockout JS with nested View Models?

查看:54
本文介绍了如何使用“with”使用嵌套的View Models在Knockout JS中绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个模板来填写多人的表单。我不想进入foreach绑定或模板。我只是尝试使用一个按钮将简单形式的所有数据保存为5个输入,该按钮将人员添加到observableArray并清除下一个人的表单。

I am trying to write a template to fill a form for multiple persons. I do not want to go in for "foreach" binding or template. I am just trying to save all the data in the simple form with 5 inputs using a button that will add the person to the observableArray and clear the form for the next person.

我在下面粘贴了我的整个代码:

I have pasted my entire code below:

<html>
<head>
    <title>Test Knockouts</title>
</head>
<body>
    <div id="rootDiv">
        <ul data-bind="with: Person">
            <li data-bind="event: { click: $data.setupPersonTypeForm.bind($data, 'Member') }">
                <a href="#" aria-controls="home">
                    <span class="radio-label">Member</span>
                </a>
            </li>
            <li data-bind="event: { click: $data.setupPersonTypeForm.bind($data, 'Guest') }">
                <a href="#" aria-controls="messages">
                    <span class="radio-label">Guest</span>
                </a>
            </li>
            <li data-bind="event: { click: $data.setupPersonTypeForm.bind($data, 'Employee') }">
                <a href="#" aria-controls="profile">
                    <span class="radio-label">Employee</span>
                </a>
            </li>
        </ul>
        <div>
            Person Name:
            <input type="text" data-bind="text: PersonName" /><br />
            Person Age:
            <input type="text" data-bind="text: PersonAge" /><br />
            Person Type:
            <input type="text" data-bind="text: PersonType" /><br />
            Person Country:
            <input type="text" data-bind="text: PersonCountry" /><br />
            Person NetWorth:
            <input type="text" data-bind="text: PersonNetWorth" />
        </div>
    </div>

    <script src="jquery-2.1.4.js"></script>
    <script src="knockout-3.4.0.js"></script>

    <script type="text/javascript">

        $(document).ready(function (e) {

            var element = document.getElementById("rootDiv");
            ko.applyBindings(rootVM, element);

            var RootVM = function (data) {
                var self = this;

                self.Id = ko.observable();
                self.Name = ko.observable();
                self.Location = ko.observable();
                self.TypeId = ko.observable();
                self.Age = ko.observable();

                self.Person = ko.observableArray([new PersonVM()]);
            }
            var rootVM = new RootVM();


            var PersonVM = function (data) {
                var self = this;

                self.Id = ko.observable();
                self.PersonName = ko.observable();
                self.PersonType = ko.observable();
                self.PersonAge = ko.observable();
                self.PersonCountry = ko.observable();
                self.PersonNetWorth = ko.observable();

                self.PersonTypeIdPlaceholder = ko.observable();
                self.ShowEmployeeTitleField = ko.observable(false);

                self.setupPersonTypeForm = function (personType) {

                    self.ShowEmployeeTitleField(false);

                    switch (personType) {

                        case "Member":
                            self.PersonTypeIdPlaceholder("Member ID");
                            break;
                        case "Guest":
                            self.PersonTypeIdPlaceholder("Guest ID");
                            break;
                        case "Employee":
                            self.PersonTypeIdPlaceholder("Employee ID");
                            self.ShowEmployeeTitleField(true);
                            break;
                    }
                }

                self.setupPersonTypeForm('Member');

                self.Property = ko.observableArray([new PropertyVM()]);
            }

            var PropertyVM = function (data) {
                var self = this;

                self.Id = ko.observable();
                self.PropertyPlace = ko.observable();
                self.PropertySize = ko.observable();
                self.PropertyName = ko.observable();
                self.PropertyAge = ko.observable();
            }
        });
    </script>
</body>
</html>

我收到以下错误:


knockout-3.4.0.js:72未捕获的ReferenceError:无法处理
绑定with:function(){return Person}消息:Person不是
定义的

knockout-3.4.0.js:72 Uncaught ReferenceError: Unable to process binding "with: function (){return Person }" Message: Person is not defined

我在哪里错了?

任何帮助都将不胜感激! 。

Any help would be appreciated!.

推荐答案

截至此行:

ko.applyBindings(rootVM, element);

... rootVM undefined ,您尚未为其指定任何值。你想把它移到之后你的

...rootVM is undefined, you haven't assigned it any value yet. You want to move that to after your

var rootVM = new RootVM();

...反过来需要

var PersonVM = function (data) { ... };

...因为它使用 PersonVM

...since it uses PersonVM.

只有声明被悬挂,而不是分配。当你有:

Only declarations are hoisted, not assignments. When you have:

(function() {
    console.log(foo);

    var foo = 42;
})();

...你看 undefined ,而不是42,因为该代码被解释为:

...you see undefined, not 42, because that code is interpreted as:

(function() {
    var foo = undefined;

    console.log(foo);

    foo = 42;
})();

这一切都发生在您的代码中。

That's happening all through your code.

至少还有其他一些问题:

There are at least a couple of other issues as well:


  1. 你正在使用 Person 好像它只是一件事,但你把它定义为一系列事物。解决上述问题后,您遇到的问题是单击事件无法绑定,因为数组没有 setupPersonTypeForm 方法(你的,而不是里面的数组)。

  1. You're using Person as though it were a single thing, but you're defining it as an array of things. Once you fix the issue above, you have the issue that the click event can't be bound because arrays don't have a setupPersonTypeForm method (your Person does, not the array it's inside).

你'重新使用列表下面只存在于 Person 上的属性,但只使用列表上的:Person 。 / p>

You're using properties below the list that only exist on Person, but only using the with: Person on the list.

如果您的目标是拥有一个人员列表,并且能够添加/编辑该列表中的人员一个表格,我在这里的答案显示了如何做一些几乎完全相同的事情,只有项目而不是人。

If your goal is to have a list of people, and to be able to add/edit people on that list with a form, my answer over here shows how to do something nearly identical, just with "projects" rather than "people".

以下是该答案重复上下文的简单示例:

Here's the simple example in that answer duplicated for context:

function Project(title, priority) {
  this.title = ko.observable(title || "");
  this.priority = ko.observable(priority || "Medium");
}


function ProjectViewModel() {
  var self = this;
  this.priorityOptions = ko.observableArray(["High", "Medium", "Low"]);
  this.projects = ko.observableArray();
  this.editing = ko.observable(new Project());
  this.addProject = function() {
    this.projects.push(this.editing());
    this.editing(new Project());
  };
}

ko.applyBindings(new ProjectViewModel(), document.body);

<div>
  <div>
    <label>
      Title:
      <input type="text" data-bind="value: editing().title, valueUpdate: 'input'">
    </label>
  </div>
  <div>
    <label>
      Priority:
      <select data-bind='options: priorityOptions, value: editing().priority'></select>
    </label>
  </div>
  <div>
    <button type="button" data-bind="click: addProject, enable: editing().title">Add Project</button>
  </div>
  <hr>
  <div>Projects:</div>
  <div data-bind="foreach: projects">
    <div>
      <span data-bind="text: title"></span>
      (<span data-bind="text: priority"></span>)
    </div>
  </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

在评论中你问过:



  1. 如果我们为每个项目都有一些子类别,我想在每个特定项目中添加几个子类别项。在哪个viewmodel中放置addSubCategory函数。你如何跟踪每个孙子项目?


你只需重复相同的结构,嵌套。例如,我们可以在项目中轻松添加任务列表。

You just repeat the same structure, nested. For instance, we can readily add a list of "tasks" in our "project"s.



  1. 为什么我们不能使用with绑定?淘汰赛有限制吗?


如果你愿意,可以。我没有在原始示例中,因为我在项目中只有两个字段,但您可以在上面添加 data-bind =with:editing来包装那些在中使用代替。

You can if you like. I didn't in the original example because I only had two fields on a project, but you could put data-bind="with: editing" in the above to wrap those in a with instead.

这是一个包含任务并使用绑定(我已经从上面改为编辑 editProject ,因为现在我们还有 editTask ):

Here's an example with tasks and using with bindings (I've changed editing from the above to editProject since now we also have editTask):

function Task(label, difficulty) {
  this.label = ko.observable(label);
  this.difficulty = ko.observable(difficulty || "Normal");
}

function Project(title, priority) {
  this.title = ko.observable(title || "");
  this.priority = ko.observable(priority || "Medium");
  this.tasks = ko.observableArray();
  this.editTask = ko.observable(new Task());
  this.addTask = function() {
    this.tasks.push(this.editTask());
    this.editTask(new Task());
  };
}


function ProjectViewModel() {
  var self = this;
  this.priorityOptions = ko.observableArray(["High", "Medium", "Low"]);
  this.difficultyOptions = ko.observableArray(["Hard", "Normal", "Easy"]);
  this.projects = ko.observableArray();
  this.editProject = ko.observable(new Project());
  this.addProject = function() {
    this.projects.push(this.editProject());
    this.editProject(new Project());
  };
}

ko.applyBindings(new ProjectViewModel(), document.body);

ul {
  margin-top: 0;
  margin-bottom: 0;
}

<div>
  <!-- Added a new div with a 'with' binding -->
  <div data-bind="with: editProject">
    <div>
      <label>
        Title:
        <input type="text" data-bind="value: title, valueUpdate: 'input'">
      </label>
    </div>
    <div>
      <label>
        Priority:
        <select data-bind='options: $parent.priorityOptions, value: priority'></select>
      </label>
    </div>
    <div style="padding-left: 3em">
      Tasks for this project:
      <div style="padding-left: 2em">
        New task:
        <div data-bind="with: editTask">
          <div>
            <label>
              Difficulty:
              <select data-bind='options: $root.difficultyOptions, value: difficulty'></select>
            </label>
          </div>
          <div>
            <label>
              Label:
              <input type="text" data-bind="value: label, valueUpdate: 'input'">
            </label>
          </div>
        </div>
        <button type="button" data-bind="click: addTask, enable: editTask().label">Add Task</button>
      </div>
      <div data-bind="foreach: tasks">
        <div>
          [<span data-bind="text: difficulty"></span>]
          <span data-bind="text: label"></span>
        </div>
      </div>
    </div>
  </div>
  <div>
    <button type="button" data-bind="click: addProject, enable: editProject().title">Add Project</button>
  </div>
  <hr>
  <div>Projects:</div>
  <div data-bind="foreach: projects">
    <div>
      <span data-bind="text: title"></span>
      (<span data-bind="text: priority"></span>)
    </div>
    <ul data-bind="foreach: tasks">
      <li>[<span data-bind="text: difficulty"></span>]: <span data-bind="text: label"></span></li>
    </ul>
  </div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

这篇关于如何使用“with”使用嵌套的View Models在Knockout JS中绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆