0

尝试绑定text到视图模型之外的全局函数会引发以下错误:

knockout.js:60 Uncaught ReferenceError: Unable to process binding "foreach: function (){return names }" Message: Unable to process binding "text: function (){return myFunction($data) }" Message: myFunction is not defined

在线复制

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.prototype.myFunction = function(){
    return this + '--';
}

在线复制

为什么是这样?难道没有更好的方法将全局函数应用于text绑定吗?

4

2 回答 2

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);
于 2016-06-10T14:14:53.393 回答
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,或者,如果你已经将它附加到你的根 viewModel,你可以这样做$root.myFunction


另一种处理方法是将函数直接添加到绑定上下文中。这允许无论当前 viewModel 是什么都可以引用它。

“foreach”绑定处理程序和模板绑定处理程序上的“as”选项是向绑定上下文添加内容的一种方式;但是我为此使用了“let” bindingHandler,let bindingHandler 不是 KO 的官方部分,但经常被核心贡献者之一 Michael Best 推荐。

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 -->

在上面的示例中,您可以myFunctionlet绑定中的任何位置引用,而不管您的 viewModel 有多少层。

于 2016-06-10T14:28:35.413 回答