【问题标题】:Knockout - error with binding to template wrapper淘汰赛 - 绑定到模板包装器时出错
【发布时间】:2013-11-01 17:59:39
【问题描述】:

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

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

在第一种方法中,我创建了一个单独的 viewModel,将其附加到现有的主 viewModel 上,它似乎会一直运行,直到它尝试更新主 viewModel 中的“成功”值。此时,它将值设置为 [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));

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

    (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));

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

【问题讨论】:

    标签: javascript knockout.js model-binding


    【解决方案1】:

    我想通了。我知道我的绑定处理程序存在问题。我实际上是让我的绑定变得更复杂,这是它需要的。我只需要在 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's 对19732545 的回答,它帮助我重新审视了我正在做的事情,这有助于简化问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 2016-07-03
      • 2018-09-05
      相关资源
      最近更新 更多