将文本绑定到全局函数

时间:2016-06-10 13:53:10

标签: knockout.js knockout-3.0 knockout-3.2

尝试将text绑定到viewmodel之外的全局函数会引发以下错误:

  

knockout.js:60未捕获的ReferenceError:无法处理绑定“foreach:function(){return names}”   消息:无法处理绑定“text:function(){return myFunction($ data)}”   消息:myFunction未定义

Reproduction online

HTML

<ul data-bind="foreach: names">
    <li data-bind="text: myFunction($data)"></li>
</ul>

JS

function myFunction(text){
    return text + '--';
}

function demoViewModel() {
    self.names = ['a', 'b', 'c'];

    return self;
}

var mm = new demoViewModel();

ko.applyBindings(mm);

相反,如果我扩展String对象并按以下方式应用该函数,它将按预期工作:

<li data-bind="text: $data.myFunction()"></li>

扩展String对象:

String.prototype.myFunction = function(){
    return this + '--';
}

Reproduction online

这是为什么?是否有更好的方法将全局函数应用于text绑定?

2 个答案:

答案 0 :(得分:1)

这是我建议做你想做的事。您的功能未在该范围内定义。在这里,你实际上将每个名称(甚至它可以是一个对象)绑定到视图模型之外的函数
示例:https://jsfiddle.net/1hz10pkc/2/
HTML:

<ul data-bind="foreach: names">
    <li data-bind="text:name "></li>
</ul> 

JS

var myFunction = function(text){
  var self = this;
  self.name = text + "--" ; 
}

function demoViewModel() {
   var self = this;
   var arr =  ['a', 'b', 'c'];
   self.names = ko.observableArray($.map(arr, function (element) {
        return new myFunction(element);
    }));
}
var mm = new demoViewModel();

ko.applyBindings(mm);

答案 1 :(得分:1)

要从淘汰模板中引用您的函数,需要将其附加到ViewModel。在上面的简单案例中,您只需将其附加到demoViewModel并直接在模板中引用它:

function myFunction(text){
    return text + '--';
}

function demoViewModel() {
    var self = this;
    self.names = ['a', 'b', 'c'];
    self.myFunction = myFunction;

    return self;
}

ko.applyBindings(new demoViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: names">
    <li data-bind="text: myFunction($data)"></li>
</ul>

这不是一个真正的“全局”函数,它只是一个标准的viewModel属性,如果您最终使用嵌套绑定上下文,则必须执行$parents[n].myFunction,或者如果您已将其附加到root viewModel,你可以做$root.myFunction

另一种处理方法是直接将函数添加到binding context。无论当前的viewModel是什么,都允许引用它。

“foreach”绑定处理程序和模板绑定处理程序的“as”选项是向绑定上下文添加内容的一种方法;但是为了这个目的,我使用了一个“let”bindingHandler,let bindingHandler不是KO的官方部分,而是Michael Best的often recommended,是其中一个核心贡献者。

function myFunction(text){
    return text + '--';
}

function demoViewModel() {
    var self = this;
    self.names = ['a', 'b', 'c'];
    self.myFunction = myFunction;

    return self;
}


//Let binding Handler
ko.bindingHandlers['let'] = {
    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // Make a modified binding context, with extra properties, and apply it to descendant elements
        var innerContext = bindingContext.extend(valueAccessor());
        ko.applyBindingsToDescendants(innerContext, element);

        return { controlsDescendantBindings: true };
    }
};
ko.virtualElements.allowedBindings['let'] = true;

ko.applyBindings(new demoViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- ko let: {
    myFunction: myFunction
} -->
  <ul data-bind="foreach: {
      data: names,
      at: 'name'
  }">
      <li data-bind="text: myFunction($data)"></li>
  </ul>
<!-- /ko -->

在上面的示例中,您可以在myFunction绑定中的任何位置引用let,无论您有多少级别的viewModel。