0

我在 knockoutjs 网站上找到了示例。在这里,它们将值绑定到多选列表框。但他们使用的是非常简单的可观察数组。 availableCountriesselectedCountries

<p>
    Choose some countries you'd like to visit:
    <select data-bind="options: availableCountries, selectedOptions: chosenCountries" size="5" multiple="true"></select>
</p>

<script type="text/javascript">
    var viewModel = {
        availableCountries : ko.observableArray(['France', 'Germany', 'Spain']),
        chosenCountries : ko.observableArray(['Germany']) // Initially, only Germany is selected
    };

    // ... then later ...
    viewModel.chosenCountries.push('France'); // Now France is selected too
</script>

但是我的模型太复杂了,提到我模型的部分是json格式。

"JobOrderDelivTranscript" : [{
        "TranscriptType" : {
            "Id" : 1,
            "Name" : null,
            "CreatedBy" : 0,
            "CreatedDate" : "0001-01-01T00:00:00",
            "ModifiedBy" : 0,
            "ModifiedDate" : "0001-01-01T00:00:00",
            "IsActive" : false,
            "EntityStatus" : 0,
            "ErrorMessage" : null,
            "ExternalID" : 0,
            "ExternalSystemID" : 0
        },
        "Id" : 1,
        "Name" : null,
        "CreatedBy" : 0,
        "CreatedDate" : "0001-01-01T00:00:00",
        "ModifiedBy" : 0,
        "ModifiedDate" : "0001-01-01T00:00:00",
        "IsActive" : false,
        "EntityStatus" : 0,
        "ErrorMessage" : null,
        "ExternalID" : 0,
        "ExternalSystemID" : 0
    }, {
        "TranscriptType" : {
            "Id" : 2,
            "Name" : null,
            "CreatedBy" : 0,
            "CreatedDate" : "0001-01-01T00:00:00",
            "ModifiedBy" : 0,
            "ModifiedDate" : "0001-01-01T00:00:00",
            "IsActive" : false,
            "EntityStatus" : 0,
            "ErrorMessage" : null,
            "ExternalID" : 0,
            "ExternalSystemID" : 0
        },
        "Id" : 2,
        "Name" : null,
        "CreatedBy" : 0,
        "CreatedDate" : "0001-01-01T00:00:00",
        "ModifiedBy" : 0,
        "ModifiedDate" : "0001-01-01T00:00:00",
        "IsActive" : false,
        "EntityStatus" : 0,
        "ErrorMessage" : null,
        "ExternalID" : 0,
        "ExternalSystemID" : 0
    }
]

这里我的“ selectedCountries ”将是 JobOrderDelivTranscript()。如果我选择第一个选项,它应该与 JobOrderDelivTranscript()[0].TranscriptType.Id 映射。在他们的示例中,他们使用的是字符串数组,但我必须绑定复杂的数据。我怎样才能做到这一点。

即使我尝试使用自定义绑定

ko.bindingHandlers['selectedCustomOptions'] = {
            getSelectedValuesFromSelectNode: function (selectNode) {
                var result = [];
                var nodes = selectNode.childNodes;
                for (var i = 0, j = nodes.length; i < j; i++) {
                    var node = nodes[i], tagName = ko.utils.tagNameLower(node);
                    if (tagName == "option" && node.selected)
                        result.push(ko.selectExtensions.readValue(node));
                    else if (tagName == "optgroup") {
                        var selectedValuesFromOptGroup = ko.bindingHandlers['selectedCustomOptions'].getSelectedValuesFromSelectNode(node);
                        Array.prototype.splice.apply(result, [result.length, 0].concat(selectedValuesFromOptGroup)); // Add new entries to existing 'result' instance
                    }
                }
                return result;
            },
            'init': function (element, valueAccessor, allBindingsAccessor) {
                ko.utils.registerEventHandler(element, "change", function () {
                    var value = valueAccessor();
                    var valueToWrite = ko.bindingHandlers['selectedCustomOptions'].getSelectedValuesFromSelectNode(this);
                    ko.jsonExpressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
                });
            },
            'update': function (element, valueAccessor) {
                if (ko.utils.tagNameLower(element) != "select")
                    throw new Error("values binding applies only to SELECT elements");

                var newValue = ko.utils.unwrapObservable(valueAccessor());
                if (newValue && typeof newValue.length == "number") {
                    var nodes = element.childNodes;
                    for (var i = 0, j = nodes.length; i < j; i++) {
                        var node = nodes[i];
                        if (ko.utils.tagNameLower(node) === "option")
                            ko.utils.setOptionNodeSelectionState(node, arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0);
                    }
                }
            }
        };

        function arrayIndexOf (array, item) {
            if (typeof Array.prototype.indexOf == "function")
                return Array.prototype.indexOf.call(array, item);
            for (var i = 0, j = array.length; i < j; i++)
                if (array[i].TranscriptType.Id() === item.Id)
                    return i;
            return -1;
        }

我已经选择了选项,但 json 数据没有得到更新。

有什么简单的方法吗?

提前致谢。

4

1 回答 1

1

我不是 100% 我理解你的问题,但似乎你正在尝试使用 selectedOptions 绑定绑定到一个复杂的对象。有两种方法可以做你想做的事。第一种是结合使用 optionsValue 绑定和计算来将您的绑定 id 拉到对象根级别(不幸的是,optionsValue 绑定仅适用于根,因此optionsValue: 'TranscriptType.Id'不起作用)。

<p>Choose some countries you'd like to visit:</p>
<select data-bind="options: availableCountries, optionsText: optionsText, 
      optionsValue: 'id', selectedOptions: 
      chosenCountries" size="5" multiple="true"></select>

<p data-bind="text: ko.toJSON(chosenCountries)">
</p>

var JobOrderDelivTranscript = function(id) {
    var self = this;
    this.TranscriptType = {
        Id : id
    }
    this.id = ko.computed(function() {
        return self.TranscriptType.Id
    });
};

http://jsfiddle.net/madcapnmckay/6K6kH/

第二种方法是不使用 optionsValue,在这种情况下 KO 将使用对象引用来测试相等性。只要您在您的 selectedCounties 数组中保留相同的对象引用,一切都会正常工作。

var viewModel = function () {
    var self = this;
    this.availableCountries = ko.observableArray([
        new JobOrderDelivTranscript("Some Transcript 1"),
        new JobOrderDelivTranscript("Some Transcript 2"),
        new JobOrderDelivTranscript("Some Transcript 3")]);

    this.chosenCountries = ko.observableArray([ self.availableCountries()[0] ]);

    this.optionsText = function(option) {
        return option.TranscriptType.Id;
    };        
};

var vm = new viewModel();
vm.chosenCountries.push(vm.availableCountries()[1]);

http://jsfiddle.net/madcapnmckay/hmsqf/

两种方式各有利弊,这取决于您的具体情况,哪种方式是正确的。

编辑

要使用映射插件做同样的事情,您需要使用“高级用法”下的文档中介绍的映射选项。

这是一个你应该能够适应的例子。

http://jsfiddle.net/madcapnmckay/hmsqf/2/

为了更好地构建您的代码,我建议创建许多 javascript 类,就像我在 Order 示例中所做的那样,这允许将逻辑包含在离散块中。我也不建议使用旧的 jquery 选择器,许多 KO 初学者认为可以将两者混合使用。在我看来,它稀释了视图模型和视图之间的关注点分离。为什么$(selector).click在可以使用click绑定时使用 a 。

希望这可以帮助。

于 2012-05-23T17:34:54.973 回答