1

我刚刚开始尝试使用 JavaScript、JQuery 和 Knockout.js(我通常在 Java 中的服务器端工作)并且它非常出色 - 但是我已经碰壁了,我非常怀疑我正在做,无论我想做什么,“按书本”。

我在这里为它创建了一个小提琴:http: //jsfiddle.net/kcyhw/

我的使命:

  • 我需要创建一个可以在整个网站上重复使用的模板。外汇。一个包含创建、编辑和删除用户的可能性的模板——这将使在“用户配置”窗口中创建用户变得容易,或者作为向导的一部分。无论哪种方式,控制一切的逻辑都应该是相同的。然而,除了为数据共享同一个arrayObservable之外,选择选项当然不应该互相观察。现在,它完全是一个选择框。我正在使用 JQuery.serialize 将整个表单转换为键值,以发送到服务器,因此重要的是我不仅要获取值,还要将其“保存”在选择框的 value 属性中.

我的问题:

  • 我根本无法弄清楚 Knockout.js 和选择框是如何连接的。在选择框和属性部分中,所有对象都通过它们各自的值(id 和全名)很好地显示。使用 jQuery 进行序列化时,它只会打印:“perselect="... 所以它没有得到值。

我尝试了以下方法:

  • 在数据绑定中使用 optionValue - 它可以工作,并且绑定到“值”,但是,我可以看到它“接管”了我的绑定,并杀死了我从对象中检索到的文本。我删除了它,然后继续...

  • 计算值,但是它没有解决,因为模板需要(据我所知)一个文字对象,并且函数不能引用此类对象中的其他属性。

  • 创建了我自己的绑定,因此我可以获得对元素(选择框)和所有其他绑定值的引用。在这个函数中,我尝试使用 jQuery 在传入的元素上设置属性“值”,但是它不起作用。我还可以看到,绑定被调用了 4 次(这可能是因为它调用了 init 然后为我创建的每个包含选择框的模板进行更新)。

对我来说,看起来我已经创造了一个该死的混乱,如果一些聪明的人能指出我如何解决这个问题的正确方向,我将不胜感激。资源、代码片段、建议……无论你得到什么。

编码:

<html>

<head>
<script src="javascript/jquery-1.10.2/jquery-1.10.2.js"></script>
<script src="javascript/knockout-2.3.0/knockout-2.3.0.js"></script>
<script src="javascript/knockout.mapping-master-2.0/knockout.mapping-latest.js"></script>
<script type="text/javascript" src="javascript/json2-2.0/json2.js"></script>
<title>A Knockout Demo</title>


<script>
    /**
     * JQuery Function
     */
    $(document).ready(function() {
        // Domain Object
        var Person = function(id, fullname) {
            var self = this;
            self.id = id;
            self.fullname = fullname;
        };

        // Knockout Model
        var KoModel = function() {
            var self = this;

            // Declare observables
            self.persons = ko.observableArray();

            // Allows observables to share an array without observing each other
            self.createPersonSelector = function(namevalue) {
                var person = new Object();
                person.selectedPerson = ko.observable();
                person.name = namevalue;
                return person;
            }

            // Prints a serialized string which could be sent to the server
            self.printFormElements = function(formElements) {
                alert($(formElements).serialize());
            }

            // Will change the person select value, to a real value
            self.changePersonSelectValue = function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var value = valueAccessor(), allBindings = allBindingsAccessor();

                // Next, whether or not the supplied model property is observable, get its current value
                var valueUnwrapped = ko.unwrap(value);

                // Now manipulate the DOM element
                var $eleme = $(element);

                if ($eleme == null) {
                    return;
                }

                // Change to item number two in the list *doesn't work*.
                $eleme.val(2);
            };

            // Person selectbox value binding
            ko.bindingHandlers.personSelect = {
            init : function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                self.changePersonSelectValue(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
            },
            update : function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                self.changePersonSelectValue(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
            }
            };

            // Put some test-data into the array
            self.persons.push(new Person(1, 'Martin Smith'));
            self.persons.push(new Person(2, 'Andy Gregersen'));
            self.persons.push(new Person(3, 'Thomas Peep'));
        };

        // Apply bindings
        ko.applyBindings(new KoModel());
    });
</script>

<script type="text/html" id="person-template">
<span>Choose ID: </span><select data-bind="options: $root.persons, optionsText: 'id', personSelect: true, value:selectedPerson, attr: {'name': name, 'id': name}"></select></br>
<span>ID:</span> <span data-bind="text: selectedPerson().id"></span></br>
<span>Full Name: </span> <span data-bind="text: selectedPerson().fullname"></span></br>
</script>
<body>
    <h1>Person Select One</h1>
    <form data-bind="submit: printFormElements">
        <div
            data-bind="template: { name: 'person-template', data:createPersonSelector('personselect')}"></div>
        <button type="submit">Submit</button>
        </br>
    </form>

    <h1>Person Select Two</h1>
    <form data-bind="submit: printFormElements">
        <div
            data-bind="template: { name: 'person-template', data:createPersonSelector('personselecttwo')}"></div>
        <button type="submit">Submit</button>
        </br>
    </form>
</body>

</html>
4

1 回答 1

0

对我来说,最简单的回答方法是改变很多我可能会做不同的事情。阻碍您的主要问题是您使用 jQuery 来处理可以由 KO 以更简单的方式处理的事情。

以下是我要更改的内容,要查看完整结果,请查看此小提琴(根本不使用 jQuery)。

将您的模型简化为如下所示:

var KoModel = function() {
    var self = this;

    // Declare observables
    self.persons = ko.observableArray();

    // Prints a serialized string which could be sent to the server
    self.printFormElements = function() {
        alert(ko.mapping.toJSON(self));
    }

    // Hold selected person
    self.selectedPersons = ko.observableArray();
};

需要注意的几点:

  • “打印”功能现在使用映射插件,非常适合序列化视图模型;
  • 它要短得多。不再需要“CreatePersonSelector”和“changePersonSelectValue”函数,也不再需要自定义绑定;
  • 现在selectedPersons是一个可观察的,并且是一个数组,因为视图可能是一个多选;
  • 在旁注中,我已将测试值添加到 ViewModel 之外;

这对应于以下用于启动模板的视图:

<div data-bind="template: { name: 'person-template' }"></div>

我现在已经删除了该data位。这意味着此代码的每个实例都将绑定到(相同的)$root视图模型。如果您不希望这样,我建议您创建一个容器视图模型来容纳多个KoModels.

模板如下所示:

<span>Choose ID: </span>
<select data-bind="options: persons, optionsText: 'fullname', selectedOptions: selectedPersons"></select><br />
<!-- ko foreach: selectedPersons -->
<span>ID:</span> <span data-bind="text: id"></span><br />
<span>Full Name: </span> <span data-bind="text: fullname"></span><br />
<!-- /ko -->

这是简体:

  • data-bind就简单多了。您不需要摆弄value属性,因为 Knockout 会将每个属性绑定option到数组中的特定项目;
  • 这使您可以自由使用fullname文本;
  • selectedOptions位告诉 Knockout 在您的视图模型中存储选定项目的位置;
  • 选定的选项显示在 a 中,foreach因为select可能会被multiple选中。

现在ko.mapping.toJSON(self)视图模型中的调用将生成如下内容:

{
    "persons": [{
        "id": 1,
        "fullname": "Martin Smith"
    }, {
        "id": 2,
        "fullname": "Andy Gregersen"
    }, {
        "id": 3,
        "fullname": "Thomas Peep"
    }],
    "selectedPersons": [{
        "id": 2,
        "fullname": "Andy Gregersen"
    }]
}

如您所见,选定人员的列表在那里,要发送到服务器。其余的默认情况下都在那里,但映射插件可以配置得非常详细。

希望这有助于并解决您的问题!

于 2013-08-27T06:34:04.670 回答