如何在Knockout JS中的BindingHandler中获取绑定表达式

时间:2013-01-16 06:42:57

标签: javascript data-binding knockout.js

假设我有一个限制范围

<span data-bind="MyBinding: Name"></span>

我有自定义绑定

ko.bindingHandlers.MyBinding = {
   init: function (element, valueAccessor, allBindings, viewModel, context) {
        // I want to get the string "Name" here. NOT the value of Name.
   },
};

如何在处理程序中获取带有绑定表达式值的字符串?即如何获得“名称”而不是“名称的价值”。

我还需要表达式,因此传递字符串“Name”是不可行的。

<span data-bind="MyBinding: 'Name'"></span>

6 个答案:

答案 0 :(得分:2)

您需要将Name作为字符串传递而不是作为参考:

<span data-bind="MyBinding: 'Name'"></span>

ko.bindingHandlers.MyBinding = {
   init: function (element, valueAccessor, allBindings, viewModel, context) {
        var myBinding = valueAccessor(); // will contain 'Name';
        var valueOfmyBinding = viewModel[myBinding]; //value of the Name property
   },
};

您仍然可以将表达式用作字符串,因为在Javascript中,eval altough eval()是一个危险的函数:这​​里有一个示例JSFiddle

或者,如果您只需要支持像Child.Name这样的简单属性表达式,那么您可以编写自己的解析器,将字符串拆分为点,并在访问器上进行操作。

答案 1 :(得分:2)

实际上,Knockout 有一个内置的方法来做到这一点。您需要稍微调整自定义绑定(即,它变为对象而不是字符串值)。 Knockout允许您与initupdate属性一起指定preprocess属性。例如,假设我们有以下viewModel:

var app = { data: ko.observable('Hello World') };

一个简单的绑定,将传递给它的字符串完全转换为小写,并输出绑定的名称和值(视图中传递的属性显然为data):

ko.bindingHandlers.lower = {
  update: function(elem, value) {
    var obj = ko.unwrap(value());
    elem.textContent = 'Name: ' + ko.unwrap(obj.name) + 
      ' - Value: ' + ko.unwrap(obj.data).toLowerCase();
  },
  preprocess: function(value, bindingName) {
    return '{data:' + value + ', name:\'' + bindingName + '\'}';
  }
};

这就像字符串化传递给它的value属性一样简单&amp;将绑定的值转换为具有2个键的对象(此处为name&amp; value)。 Have a look。有关详细信息,请参阅Binding preprocessing

答案 2 :(得分:1)

您可以执行以下操作,因此您不会需要eval。

auto& objects = group->getObjects();
for (auto &obj : objects) {
    auto &properties = obj.asValueMap();
    cc_log(properties["type"].asString());
}

正如已经解释过的那样,您需要在绑定中将Name作为字符串值。之后,您可以使用它来逐步浏览viewmodel以检索值。要在我添加的元素中显示值     <span data-bind="MyBinding: 'Name.More.AndMore'"></span> ko.bindingHandlers.MyBinding = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { var value = valueAccessor(); var sp = value.split('.'); var current = viewModel; for(var i=0;i<sp.length;i++) { var nNode = current[sp[i]]; if ( nNode ) { current = nNode; } } $(element).html(current()); } }; 这里$(element).html(current());位于我的viewmodel中最深层,因此可以调用它,返回值可用于更新html。

答案 3 :(得分:1)

我建议使用另一个绑定来转移属性的名称。

<div data-bind="myBinding: content, nameOfProp:'content'"></div>

ko.bindingHandlers.myBinding = {
    init: function(element, valueAccessor, allBindings, viewModel, context) {
      var nameOfProp = allBindings.get("nameOfProp");
    };
  }

JSFiddle

答案 4 :(得分:1)

我喜欢上面所说的pavel-chervov。如果你不介意使用一些jQuery,那就用类似的方式了:

<span data-binding-name="Name" data-bind="MyBinding: Name"></span>

ko.bindingHandlers.MyBinding = {
    init: function (element, valueAccessor, allBindings, viewModel, context) {
        var nameOfProp = $(element).data('binding-name');
    },
};

答案 5 :(得分:0)

I'm a bit late to the party on this, but here's what I did, and it works like a charm:

JS:

ko.bindingHandlers.myHandler = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var regex = /return ([^\s]+)\s*}/;

        //accessor will contain whatever expression was used in data-bind
        //so in this example it will be "myProp.childProp"
        var accessor = regex.exec(valueAccessor.toString())[1];

        //...
},
//...

HTML:

<div data-bind="myHandler: myProp.childProp"></div>

So the value of accessor (in case you missed the comment) will be "myProp.childProp"