I am having a problem getting the knockout model to update when a user uses the PageDown button bar to make changes to the editor text. Any typing, pasting, or cutting works fine but the button bar actions do not.
I have tried adding a hook
for onPreviewRefresh
to the editor but that never seems to fire.
Here is a Fiddle showing the issue. If you type test
into the editor, test
will show up in the preview section. However, if you type test
into the editor and then use the menu bar to make test
bold then the preview section does not see this update until you type another character.
This is the custom binding that I am using to initialize the PageDown editor:
var ME = {};
ME.MarkdownConverter = Markdown.getSanitizingConverter();
ME.MarkdownCounter = 0;
ko.bindingHandlers.markdownEditor = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
++ME.MarkdownCounter;
// Create the elements needed for a new PageDown editor.
$(element).append($('<div id="wmd-button-bar-' + ME.MarkdownCounter + '" class="wmd-button-bar"></div>'));
$(element).append($('<textarea id="wmd-input-' + ME.MarkdownCounter + '" class="wmd-input"></textarea>'));
// Make sure the textarea is properly binded up so that the view model is updated.
var newBindings = { textInput: valueAccessor };
ko.applyBindingAccessorsToNode($('#wmd-input-' + ME.MarkdownCounter)[0], newBindings, viewModel);
// Create the editor and apply to the new elements ensuring that we detect all
// changes from the wmd-button-bar.
var editor = new Markdown.Editor(ME.MarkdownConverter, "-" + ME.MarkdownCounter);
editor.hooks.chain("onPreviewRefresh", function () {
var value = valueAccessor();
debugger;
value($('#wmd-input-' + ME.MarkdownCounter).val());
});
editor.run();
return { controlsDescendantBindings: true };
}
};
The value update isn't triggered because the value is set programmatically, which doesn't trigger the textarea's change event.
The onPreviewRefresh
event is not triggered because there is no preview element. As a workaround you can add the element and hide it:
var ME = {};
ME.MarkdownConverter = Markdown.getSanitizingConverter();
ME.MarkdownCounter = 0;
ko.bindingHandlers.markdownText = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
$(element).addClass('markdown-text');
},
update: function(element, valueAccessor, allBindings) {
var value = valueAccessor();
var valueUnwrapped = ko.unwrap(value);
$(element).html(ME.MarkdownConverter.makeHtml(valueUnwrapped));
}
};
ko.bindingHandlers.markdownEditor = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
++ME.MarkdownCounter;
// Create the elements needed for a new PageDown editor.
$(element).append($('<div id="wmd-button-bar-' + ME.MarkdownCounter + '" class="wmd-button-bar"></div>'));
$(element).append($('<textarea id="wmd-input-' + ME.MarkdownCounter + '" class="wmd-input"></textarea>'));
// if no preview element is found, onPreviewRefresh is not triggered
$(element).append('<div style="display: none" class="wmd-panel wmd-preview" id="wmd-preview-' + ME.MarkdownCounter + '"></div>');
var $input = $('#wmd-input-' + ME.MarkdownCounter);
// Make sure the textarea is properly binded up so that the view model is updated.
var newBindings = { textInput: valueAccessor };
ko.applyBindingAccessorsToNode($input[0], newBindings, viewModel);
// Create the editor and apply to the new elements ensuring that we detect all
// changes from the wmd-button-bar.
var editor = new Markdown.Editor(ME.MarkdownConverter, "-" + ME.MarkdownCounter);
editor.hooks.chain("onPreviewRefresh", function () {
$input.change();
});
editor.run();
return { controlsDescendantBindings: true };
}
};
var vm = { noteText: ko.observable('') };
ko.applyBindings(vm);