【问题标题】:How to access the observables in custom bindings when using Knockout-ES5使用 Knockout-ES5 时如何访问自定义绑定中的可观察对象
【发布时间】:2013-06-07 23:23:44
【问题描述】:

如果模型属性是 ko.observable(),则可以在自定义绑定中按如下方式访问这些属性。

var observable = valueAccessor();

当使用 Knockout-ES5 插件时,如何在自定义绑定中获取 observable?检查下面的代码并查找注释“如何在此处获取 propertyName?”

JS Fiddle when not using Knockout-ES pluginAnother Look at Custom Bindings for KnockoutJS 友情提供

Updated fiddle with model changed to use Knockout-ES plugin

ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        //initialize datepicker with some optional options
        var options = allBindingsAccessor().datepickerOptions || {};
        $(element).datepicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            if (!ko.isObservable(observable)) {                
                console.log("Not Observable");
                //How to get propertyName here?
                //ko.getObservable(viewModel, 'propertyName');
                return;
            }
            observable($(element).datepicker("getDate"));
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).datepicker("destroy");
        });

    },
    //update the control when the view model changes
    update: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor()),
            current = $(element).datepicker("getDate");

        if (value - current !== 0) {
            $(element).datepicker("setDate", value);   
        }
    }
};

var viewModel = {
    myDate: new Date("11/01/2011"),
    setToCurrentDate: function() {
       this.myDate = new Date();   
    }
};

ko.track(viewModel);

ko.applyBindings(viewModel);

【问题讨论】:

    标签: knockout.js knockout-es5-plugin


    【解决方案1】:

    您可以将实际的 observable 传递给绑定:

    data-bind="datepicker: ko.getObservable($data, 'myDate') ..."
    

    http://jsfiddle.net/xb6vR/1/

    但这很难看。幸运的是,Knockout 确实提供了一种方法(未记录)从绑定中写入属性值:

    //handle the field changing
    ko.utils.registerEventHandler(element, "change", function () {
        var writable = valueAccessor();
        if (!ko.isObservable(writable)) {                
            var propWriters = allBindingsAccessor()._ko_property_writers;
            if (propWriters && propWriters.datepicker) {
                writable = propWriters.datepicker;
            } else {
                return;
            }
        }
        writable($(element).datepicker("getDate"));
    });
    

    http://jsfiddle.net/xb6vR/3/

    【讨论】:

    • 谢谢。我使用了将 setter 函数作为绑定的一部分传递的解决方法。 JS Fiddle。你会推荐哪一个?
    • 你是 github repo 的成员。你知道 Knockout 是否计划在使用 es5 插件时提供一种官方方式来访问 observable,即不必求助于 _ko_property_writers?
    • ES5 插件不是官方的,所以我没有直接参与它的开发。不过,我确实将其记录为issue in Github
    • 更改可能是核心淘汰赛能够提供绑定官方方式来获取作家。即使 ES5 插件添加了属性 somePropertyObservable,它也无法在绑定中访问。感谢您的链接。我选择传递属性名称而不是 setter 函数,以免在示例中使用视图模型的情况下使用 setter.call。发布了我正在使用的解决方案。让我知道你注意到它有什么问题。再次感谢您的帮助。
    【解决方案2】:

    我最终使用了传递属性名和回退到 _ko_property_writers 的组合。 JS Fiddle.

    HTML

    <input data-bind="datepicker: myDate, datePropertyName: 'myDate',
           datepickerOptions: { minDate: new Date() }" />
    

    Javascript

    ko.bindingHandlers.datepicker = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
            var _viewModel = viewModel;
            //initialize datepicker with some optional options
            var options = allBindingsAccessor().datepickerOptions || {};
            $(element).datepicker(options);
    
            //handle the field changing
            ko.utils.registerEventHandler(element, "change", function () {
                var observable = valueAccessor();
                if (!ko.isObservable(observable)) {                
                    console.log("Not Observable");
                    var datePropertyName = allBindingsAccessor().datePropertyName;
    
                    if (datePropertyName) {
                        console.log("Using datePropertyName");
                        observable = ko.getObservable(_viewModel, datePropertyName);
                    }
                    else {
                        console.log("No datePropertyName, trying _ko_property_writers");
                        var propWriters = allBindingsAccessor()._ko_property_writers;
    
                        if (propWriters && propWriters.datepicker) {
                            observable = propWriters.datepicker;
                        } else {
                            console.log("No way to get observable");
                            return;
                        }
                    }
                }
                observable($(element).datepicker("getDate"));
            });
    
            //handle disposal (if KO removes by the template binding)
            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                $(element).datepicker("destroy");
            });
    
        },
        //update the control when the view model changes
        update: function(element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor()),
                current = $(element).datepicker("getDate");
    
            if (value - current !== 0) {
                $(element).datepicker("setDate", value);   
            }
        }
    };
    
    var viewModel = {
        myDate: new Date("11/01/2011"),
        setToCurrentDate: function() {
           this.myDate = new Date();   
        }
    };
    
    ko.track(viewModel);
    
    ko.applyBindings(viewModel);
    

    【讨论】:

      【解决方案3】:

      作为对 Michael Best 回答的补充,如果您将 knockoutjs 3.0 与 es5 插件一起使用,则无法使用 allBindingsAccessor()._ko_property_writers; 访问 observable 但是我发现可以使用ko.getObservable 函数访问它。所以它应该是这样的:

      ko.bindingHandlers.myCustomBinder = {
          init: function (element, valueAccessor, allBindingsAccessor, context) {
              var observable = ko.getObservable(context, 'observableName');
          }
      }
      

      【讨论】:

      • 你如何得到'observableName'?对于此绑定的所有用户而言,它可能并不相同。
      • @CrimsonChris - 看到这个答案:stackoverflow.com/a/16994975/1053381。您不在绑定处理程序中执行 ko.getObservable,而是在 HTML 数据绑定属性中执行此操作。
      • 我最终使用了未记录的属性设置器。在 Knockout 3.3 中使用它相当干净。我们需要一个同样适用于不可观察属性的解决方案。
      【解决方案4】:

      好吧,您可以使用预处理来放置 getObservable 并在绑定处理程序中正常使用它。

      preprocess: function (markup: string) {
              console.log("markup", markup);
      
              var lastDotIndex = markup.lastIndexOf('.');
      
              if (lastDotIndex > 0) {
                  var obj = markup.substring(0, lastDotIndex);
                  var property = markup.substring(lastDotIndex + 1);
      
                  return 'ko.getObservable(' + obj + ', \'' + property + '\');';
      
              } else {
                  return 'ko.getObservable($data, \'' + markup + '\')';
              }
          },
      

      【讨论】:

      • 有了这段代码,当使用knockout es时,你会在init或者update函数中收到observable,来自valueAccessor(); var observable = valueAccessor(); // 随意使用!
      【解决方案5】:
      function es5Preprocess(val){
          var alt = val.split('.');
          var tail = alt.pop();
          if(alt.length == 0) alt.push('$data');
          tail = 'ko.getObservable( ' + alt.join('.') + ', ' + '\'' + tail + '\'' + ' )';
          return tail + ' || ' + val;
      };
      window.ko.es5.customBinding = function(name, binding){
          binding.preprocess = es5Preprocess;
          window.ko.bindingHandlers[name] = binding;
      };
      

      然后

      window.ko.es5.customBinding('contentEditable', {
          init: function(element, valueAccessor) {
              var val = valueAccessor();
              element.onblur = function() {
                  val(element.textContent);
              };
          },
          update: function(element, valueAccessor) {
              element.textContent = valueAccessor()();
          }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-08
        • 1970-01-01
        • 2017-11-25
        • 1970-01-01
        • 1970-01-01
        • 2015-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多