Question

I'm looking to create a custom Knockout binding for use with the WYSIWYG editor NicEdit http://nicedit.com/index.php . I found a fiddle example of what looked like a similar binding here for the TinyMCE library but haven't had any success in replicating for my needs.

http://jsfiddle.net/rniemeyer/GwkRQ/

Has anyone created a working custom binding for this before, or has anyone found any other work around for this? When the instance of the NicEditor is applied normally, it appears to update the value of the attached accordingly but does not trigger the knockout observable update.

As an example, using the following javascript and html does not produce a valid result.

JS here

var viewModel = {
    content: ko.observable("<p>I want this text to load and change in the editor</p>"),
};

ko.applyBindings(viewModel);
new nicEditor().panelInstance('testTextArea');

HTML here

<form method="post" action="somepage">
    <textarea id="testTextArea" name="content" style="width:100%" data-bind="value: content"></textarea>
</form>

Thanks for any insights.

Was it helpful?

Solution

I came up with the following custom binding which seems to work. I use a bit of JQuery, but not that much, so you can always replace it with something non-JQuery.

The custom binding:

ko.bindingHandlers.nicedit = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        var area = new nicEditor({fullPanel : true}).panelInstance(element.id, {hasPanel : true});
        $(element).text(ko.utils.unwrapObservable(value)); 

        // function for updating the right element whenever something changes
        var textAreaContentElement = $($(element).prev()[0].childNodes[0]);
        var areachangefc = function() {
            value(textAreaContentElement.html());
        };

        // Make sure we update on both a text change, and when some HTML has been added/removed
        // (like for example a text being set to "bold")
        $(element).prev().keyup(areachangefc);
        $(element).prev().bind('DOMNodeInserted DOMNodeRemoved', areachangefc);
    },
    update: function(element, valueAccessor) {
        var value = valueAccessor();
        var textAreaContentElement = $($(element).prev()[0].childNodes[0]);
        textAreaContentElement.html(value());
    }
};

And how to use it:

<textarea id="area1" data-bind="nicedit: title" style="width: 640px"></textarea>

... where in my example "title" is your bound property of course.

There are two "limitations":

  • The textarea must have a DOM "id" attribute otherwise it crashes.
  • With IE (at least, version 8) the DOMNodeInserted and DOMNodeRemoved are not fired, which means that you have to type something after modifying the style of your text for it to be properly updated in your observable object.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top