Knockout - 绑定到模板包装器时出错

时间:2013-11-01 17:59:39

标签: javascript knockout.js model-binding

我正在尝试为我的文本计数跟踪器创建一个淘汰模板,以便我可以为我正在创建的页面上的每个文本区域重复此操作。 我创建了两个小提琴,展示了我一直采取的不同方法: 1. http://jsfiddle.net/ajdisalvo/9W84x/3/和 2. http://jsfiddle.net/ajdisalvo/ex2uJ/

在这两者中,我创建了一个绑定处理程序,它是我尝试绑定到的模板的包装器。

在第一种方法中,我创建了一个单独的viewModel,将它附加到现有的主viewModel,它似乎表现出来,直到它试图更新主viewModel中的值'successcesses'。此时,它将值设置为[Object object]。虽然,这个小提琴似乎非常接近于工作,但我担心我可能会创建一个递归循环,这可能是这种方法的固有缺陷。

(function (ko) {
        ko.bindingHandlers.templateWrapper = {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) {
                var existingOptions = ko.utils.unwrapObservable(valueAccessor());
                viewModel[existingOptions.itemName] = new subModel(existingOptions.dataInput(), existingOptions.maxLength);
                viewModel[existingOptions.itemName].itemText.subscribe(function (value) {
                    existingOptions.dataInput(value);
                });

                newOptions = ko.bindingHandlers.templateWrapper.buildTemplateOptions(existingOptions, viewModel[existingOptions.itemName]);
                //return ko.bindingHandlers.template.init(element, function () { return newOptions; }, allBindingsAccessor, viewModel, context);
                return { controlsDescendantBindings: true };
            },
            'update': function (element, valueAccessor, allBindingsAccessor, viewModel, context) {
                newOptions = ko.bindingHandlers.templateWrapper.buildTemplateOptions(valueAccessor(), viewModel[valueAccessor().itemName]);
                ko.bindingHandlers.template.update(element, function () { return newOptions; }, allBindingsAccessor, viewModel, context);
            },
            //extend the existing options by adding a name
            buildTemplateOptions: function (options, vm) {
                return { data: vm, name: ko.bindingHandlers.templateWrapper.templateName };
            },
            templateName: "textTrackerTemplate"
        };

        var viewModel = {
            successes: ko.observable("Test input")
        };

        var subModel = function (value, maxLength) {
            var self = this;
            self.itemText = ko.observable(value);
            self.maxLength = ko.observable(maxLength);
            self.currentLength = ko.observable(self.itemText().length);
            self.remainingLength = ko.computed(function () { return self.maxLength() - self.currentLength() });
            self.hasFocus = ko.observable(false);

            self.updateRemaining = function (data, event) {
                var e = $(event.target || event.srcElement);
                self.currentLength(e.val().length);
                if (self.currentLength() > self.maxLength()) {
                    e.val(e.val().substr(0, self.maxLength()));
                    self.ItemText(e.val());
                    self.currentLength(self.itemText().length);
                }
            };

        };

        ko.applyBindings(viewModel);

    } (ko));

在我的第二种方法中,我在绑定处理程序中使用扩展程序来添加必要的属性来填充我的计数跟踪器,但似乎扩展程序中创建的对象在敲除呈现页面时未实例化。 / p>

    (function (ko) {
        ko.bindingHandlers.templateWrapper = {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) {
                var existingOptions = ko.utils.unwrapObservable(valueAccessor());
                newOptions = ko.bindingHandlers.templateWrapper.buildTemplateOptions(existingOptions, valueAccessor);
                return ko.bindingHandlers.template.init(element, function () { return newOptions; }, allBindingsAccessor, viewModel, context);          
            },
            'update': function (element, valueAccessor, allBindingsAccessor, viewModel, context) {
                var existingOptions = ko.utils.unwrapObservable(valueAccessor());
                newOptions = ko.bindingHandlers.templateWrapper.buildTemplateOptions(existingOptions, valueAccessor);
                ko.bindingHandlers.template.update(element, function () { return newOptions; }, allBindingsAccessor, viewModel, context);
            },
            buildTemplateOptions: function (options, valueAccessor) {
                valueAccessor().dataInput = valueAccessor().dataInput.extend({ textTracker: options.maxLength });
                return { data: valueAccessor, name: ko.bindingHandlers.templateWrapper.templateName };
            },
            templateName: "textTrackerTemplate"
        };

        var viewModel = {
            successes: ko.observable("Test input")
        };

        ko.extenders.textTracker = function (target, maxLength) {
            target.itemText = ko.computed({
                read: function () {
                    return target();
                },
                write: function (value) {
                    target(value);
                }
            });

            target.maxLength = ko.observable(maxLength);
            target.currentLength = ko.observable(target.itemText().length);
            target.remainingLength = ko.computed(function () { 
                                            return target.maxLength() - target.currentLength(); });
            target.hasFocus = ko.observable(false);
            target.updateRemaining = function (data, event) {
                var e = $(event.target || event.srcElement);
                target.currentLength(e.val().length);
                if (target.currentLength() > target.maxLength()) {
                    e.val(e.val().substr(0, target.maxLength()));
                    target(e.val());
                    target.currentLength(target.itemText().length);
                }
            };
            return target;
        };

        ko.applyBindings(viewModel);

    } (ko));

提前感谢您提供的任何帮助/建议..

1 个答案:

答案 0 :(得分:0)

我明白了。我知道我的绑定处理程序存在问题。我实际上使我的绑定更复杂,它需要。我只需要在init方法中扩展值访问器,然后将其传递给模板init绑定方法。在更新语句中,我只需要使用现有的值访问器,因为它已经被扩展。这是新的绑定处理程序:

        ko.bindingHandlers.textTracker = {
            init: function (element, valueAccessor, allBindings, viewModel, context) {
                var options = ko.utils.unwrapObservable(allBindings());
                var observable = valueAccessor();
                var newValueAccessor = observable.extend({ textTracker: options });
                return ko.bindingHandlers.template.init(element,
                        function () {
                            return { data: newValueAccessor,
                                name: ko.bindingHandlers.textTracker.templateName
                            };
                        },
                        allBindings, viewModel, context);
            },
            update: function (element, valueAccessor, allBindings, viewModel, context) {
                return ko.bindingHandlers.template.update(element,
                        function () {
                            return { data: valueAccessor,
                                name: ko.bindingHandlers.textTracker.templateName
                            };
                        },
                        allBindings, viewModel, context);
            },
            templateName: "textTrackerTemplate"
        };

特别感谢RPNiemeyer's19732545的回答,这有助于我重新审视我正在做的事情,这有助于简化问题。