knockout.js - CodeMirror 自定义绑定(bind)在 "foreach"绑定(bind)内不起作用

标签 knockout.js codemirror

我已经为 CodeMirror 创建了自定义绑定(bind)。自定义绑定(bind)适用于简单的字符串,但在 foreach 绑定(bind)内,尽管添加了所有 HTML 和 CSS,但它不再被初始化。

这是一个工作片段:

var viewModel = {
  options: {
    mode: "text/x-csharp",
    lineNumbers: true
  },

  //IT WORKS
  fileContent: "public sealed class DictionaryAttribute : Attribute{}1",

  //IT DOESN'T WORK
  codes: ["public sealed class DictionaryAttribute : Attribute{}1"]
};

ko.bindingHandlers.codemirror = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var options = viewModel.options || {};
    options.value = ko.unwrap(valueAccessor());
    var editor = CodeMirror(element, options);

    editor.on('change', function(cm) {
      var value = valueAccessor();
      value(cm.getValue());
    });

    element.editor = editor;
  }
};

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<link href="https://codemirror.net/lib/codemirror.css" rel="stylesheet" />
<script src="https://codemirror.net/lib/codemirror.js"></script>
<script src="https://codemirror.net/mode/clike/clike.js"></script>

<!-- This works -->
<div data-bind="codemirror: fileContent" style="width: 700px; height: 100px"></div>

<!-- This doesn't work -->
<div data-bind="foreach: codes">
  <div data-bind="codemirror: $data" style="width: 700px; height: 100px"></div>
</div>

最佳答案

问题出在 var options = viewModel.options || {};在您的自定义绑定(bind)中。 viewModel参数指的是当前$data在上下文中,不是 applyBindings 中使用的 viewModel 。它适用于简单的字符串,因为在这种情况下, viewModel参数主要viewModel您传递给 applyBidnigs 的对象。里面foreach , viewModel将是每个 $data在你的数组中。

所以,使用$root bindingContext 的属性(property)参数代替。此外,viewModel参数在 Knockout 3.x 中已弃用:

像这样: var options = bindingContext.$root.options || {};

更新的代码片段:

var viewModel = {
  options: {
    mode: "text/x-csharp",
    lineNumbers: true
  },

  //IT WORKS
  fileContent: "public sealed class DictionaryAttribute : Attribute{}1",

  //IT DOESN'T WORK
  codes: ["public sealed class DictionaryAttribute : Attribute{}1"]
};

ko.bindingHandlers.codemirror = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var options = bindingContext.$root.options || {};
    options.value = ko.unwrap(valueAccessor());
    var editor = CodeMirror(element, options);

    editor.on('change', function(cm) {
      var value = valueAccessor();
      value(cm.getValue());
    });

    element.editor = editor;
  }
};

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<link href="https://codemirror.net/lib/codemirror.css" rel="stylesheet" />
<script src="https://codemirror.net/lib/codemirror.js"></script>
<script src="https://codemirror.net/mode/clike/clike.js"></script>

<div data-bind="codemirror: fileContent" style="width: 700px; height: 100px"></div>

<div data-bind="foreach: codes">
  <div data-bind="codemirror: $data" style="width: 700px; height: 100px"></div>
</div>


上面的代码适用于您的情况。但是,绑定(bind)期望顶部 $root反对 options属性(property)。另一种方法是添加 codeMirrorOptions绑定(bind)参数并完全删除该依赖项。

var viewModel = {
  options: {
    mode: "text/x-csharp",
    lineNumbers: true
  },

  //IT WORKS
  fileContent: "public sealed class DictionaryAttribute : Attribute{}1",

  //IT DOESN'T WORK
  codes: ["public sealed class DictionaryAttribute : Attribute{}1"]
};

ko.bindingHandlers.codemirror = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // use allBindings
    var options = ko.unwrap(allBindings().codeMirrorOptions) || {};
    options.value = ko.unwrap(valueAccessor());
    var editor = CodeMirror(element, options);

    editor.on('change', function(cm) {
      var value = valueAccessor();
      value(cm.getValue());
    });

    element.editor = editor;
  }
};

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<link href="https://codemirror.net/lib/codemirror.css" rel="stylesheet" />
<script src="https://codemirror.net/lib/codemirror.js"></script>
<script src="https://codemirror.net/mode/clike/clike.js"></script>

<div data-bind="codemirror: fileContent, codeMirrorOptions:options" style="width: 700px; height: 100px"></div>

<div data-bind="foreach: codes">
  <div data-bind="codemirror: $data, codeMirrorOptions:$parent.options" style="width: 700px; height: 100px"></div>
</div>

在这种情况下,自定义绑定(bind)独立于 viewModel。即使你的viewModel不是 $root对象,自定义绑定(bind)将起作用。

关于knockout.js - CodeMirror 自定义绑定(bind)在 "foreach"绑定(bind)内不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47567347/

相关文章:

javascript - JavaScript/Knockout.js 中的依赖注入(inject)

javascript - CodeMirror 'mode' 可以用颜色替换标签吗?

javascript - 如何在 CodeMirror 编辑器中使用 selenium 模拟关键事件

javascript - CodeMirror - 在有多个编辑器时将文本插入编辑器

javascript - 在 Codemirror/emmet 中使用 javascript 扩展缩写

javascript - 无法单击表格头元素

javascript - 在 knockout 中递归调用 foreach

javascript - 按值删除元素 a-la Knockout

javascript - 在 html 表格的 foreach 绑定(bind)内,是否可以通过 knockout 将数据绑定(bind)到选择下拉列表?

php - CodeMirror 有内容但在按键之前不会显示