I would like to integrate the CodeMirror JavaScript editor into KnockoutJS. I know there is also Ace, but it seems to me it would be easier with CodeMirror.
I already integrated custom bindings for JQueryUI widgets and QTip but these were pieces of code I found on the Internet and I then only needed to modify very small parts.
Unfortunately, it seems I've reached my limits on Javascript so I'm turning to JavaScript Sith Masters here. I don't necessarily want the whole thing written for me, pointers, and advice on how to continue would be of great help.
The piece of code I have:
The HTML (I removed custom bindings I already have on the textarea, they don't matter here)
<body>
<textarea id="code" cols="60" rows="8"
data-bind="value: condition,
tooltip: 'Enter the conditions',
codemirror: { 'lineNumbers': true, 'matchBrackets': true, 'mode': 'text/typescript' }"></textarea>
</body>
The start of my custom binding handler for CodeMirror:
ko.bindingHandlers.codemirror = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var options = valueAccessor() || {};
var editor = CodeMirror.fromTextArea($(element)[0], options);
}
};
At the moment, this does not produce JS errors but 2 text areas are displayed instead of one.
So what should I do next ?
The solutions posted before seem a bit out of date and wouldn't work for me so I have rewritten them in a form that works:
// Example view model with observable.
var viewModel = {
fileContent: ko.observable(''),
options: {
mode: "markdown",
lineNumbers: true
}
};
// Knockout codemirror binding handler
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;
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var observedValue = ko.unwrap(valueAccessor());
if (element.editor) {
element.editor.setValue(observedValue);
element.editor.refresh();
}
}
};
ko.applyBindings(viewModel);
With <div data-bind="codemirror:fileContent"></div>
as the target for code mirror to attach to this will create a new codemirror instance and pass in options from the view model if they have been set.
[edit] I have amended the update method of the codemirror binding handler to unwrap the passed valueAccessor, without that line knockout would not fire the update method when the observable is updated - it now works as you would expect it to.