Friday, May 24, 2013

Use TinyMCE in Asp.Net Single Page Application (SPA) using Knockout


In one of our project, we were creating web site using Asp.Net single page application with knockout.js. We had to add TinyMCE html editor in one of my page. It took some time to make it work.
Add binding handler for tinyMce using knock out. Please see code below

ko.bindingHandlers.tinymce = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        var options = allBindingsAccessor().tinymceOptions || {};
        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());
        var el = $(element)
        options.theme = "advanced";
      

        // Customize Tool Bars. Remove 3 lines below if you want standard tool bar
        options.theme_advanced_buttons1 = "bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,undo,redo,link,unlink";
        options.theme_advanced_buttons2 = "outdent,indent,separator,forecolor,backcolor,emoticons,separator,formatselect";
        options.theme_advanced_buttons3 = "";

        ////handle edits made in the editor. Updates after an undo point is reached.
        options.setup = function (ed) {
            ed.onChange.add(function (ed, l) {
                if (ko.isWriteableObservable(modelValue)) {
                    modelValue(l.content);
                }
            });
        };

        //handle destroying an editor 
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            setTimeout(function () { $(element).tinymce().remove() }, 0)
        });

        // $(element).tinymce(options);
        setTimeout(function () {
            $(element).tinymce(options);
            //$(element).tinymce({});

        }, 1000);

        el.html(value);

    },
    update: function (element, valueAccessor, allBindingsAccessor, context) {

        var el = $(element)
        var value = ko.utils.unwrapObservable(valueAccessor());
        var id = el.attr('id')

        //handle programmatic updates to the observable
        // also makes sure it doesn't update it if it's the same. 
        // otherwise, it will reload the instance, causing the cursor to jump.
        if (id !== undefined) {
            $(el).tinymce();
            var tinyM = tinyMCE.getInstanceById(id);
            if (tinyM !== undefined) {
                var content = tinyM.getContent({ format: 'raw' })
                if (content !== value) {
                    el.html(value);
                }
            }
        }
    }

};

Now you can bind any text area using data-bind of knockout and don’t forget to assign id to the element e.g. id=”txtPublished”.

<textarea data-bind="tinymce: publishNotes" id="txtPublished" style="height: 150px; width: 550px;"></textarea>