CodeMirror 自定义绑定在 "foreach" 绑定中不起作用
CodeMirror custom binding doesn't work inside "foreach" binding
我已经为 CodeMirror 创建了自定义绑定。自定义绑定使用一个简单的字符串,但在 foreach
绑定内部,它不再被初始化,尽管添加了所有 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 || {};
。 viewModel
参数指的是上下文中的当前 $data
,而不是 applyBindings
中使用的 viewModel。它适用于简单字符串,因为在这种情况下,viewModel
参数 是 您传递给 applyBidnigs
的主要 viewModel
对象。在 foreach
内,viewModel
将是数组中的每个 $data
。
因此,请改用 bindingContext
参数的 $root
属性。此外,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>
以上代码适用于您的情况。但是,绑定 期望 顶部 $root
对象具有 options
属性。另一种方法是将 codeMirrorOptions
参数添加到绑定并完全删除该依赖项。
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>
在这种情况下,自定义绑定独立于 viewModel。即使您的 viewModel
不是 $root
对象,自定义绑定也会起作用。
我已经为 CodeMirror 创建了自定义绑定。自定义绑定使用一个简单的字符串,但在 foreach
绑定内部,它不再被初始化,尽管添加了所有 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 || {};
。 viewModel
参数指的是上下文中的当前 $data
,而不是 applyBindings
中使用的 viewModel。它适用于简单字符串,因为在这种情况下,viewModel
参数 是 您传递给 applyBidnigs
的主要 viewModel
对象。在 foreach
内,viewModel
将是数组中的每个 $data
。
因此,请改用 bindingContext
参数的 $root
属性。此外,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>
以上代码适用于您的情况。但是,绑定 期望 顶部 $root
对象具有 options
属性。另一种方法是将 codeMirrorOptions
参数添加到绑定并完全删除该依赖项。
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>
在这种情况下,自定义绑定独立于 viewModel。即使您的 viewModel
不是 $root
对象,自定义绑定也会起作用。