Need Quality Code? Get Silver Backed

Knockout & CKEditor

12thNov

0

by Gary H

Knockout is a library which provides 2-way databinding between your script objects and UI without getting in the way. CKEditor offers a rich editing experience to an end user with dozens of plugins and styles available. In this post we will combine the two allowing a user to edit rich text documents which back seamlessly onto a JavaScript model.

Editing is the same as quarrelling with writers - same thing exactly.

Harold Ross

Bindings

To trigger a CKEditor instance on a text area we need to define a custom KnockOut binding. The binding looks like:

ko.bindingHandlers.richText = {
    init: function (element, valueAccessor) {

        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());
        var element$ = $(element);

        // Set initial value and create the CKEditor
        element$.html(value);
        var editor = element$.ckeditor().editor;

        // bind to change events and link it to the observable
        editor.on('change', function (e) {
            var self = this;
            if (ko.isWriteableObservable(self)) {
                self($(e.listenerData).val());
            }
        }, modelValue, element);


        /* Handle disposal if KO removes an editor 
         * through template binding */
        ko.utils.domNodeDisposal.addDisposeCallback(element, 
            function () {
                editor.updateElement();
                editor.destroy();
            });
    },

    /* Hook and handle the binding updating so we write 
     * back to the observable */
    update: function (element, valueAccessor) {
        var element$ = $(element);
        var newValue = ko.utils.unwrapObservable(valueAccessor());
        if (element$.ckeditorGet().getData() != newValue) {
            element$.ckeditorGet().setData(newValue);
        }
    }
}

HTML

We need a HTML page with the knockout and relevant CKEditor scripts added. To this we add a text area and a save button.

<textarea 
id="singleArea" 
    data-bind="richText: textFieldToEdit, valueUpdate: 'afterkeydown'">
    This text will be overwritten
</textarea>
<button onclick="alert('Would save: ' + ko.toJSON(vm, null, 2));">
    Save
</button>

Key points here are the valueUpdate - this will ensure that CKEditor will flush updates through to our model on every key press.

Initialisation Script

Finally we need to create a View Model and a small script to activate our knockout bindings.

function ViewModel(initialText) {
    var self = this;
    self.textFieldToEdit = ko.observable(initialText);
}
var vm = new ViewModel("Something to get started with");


$(document).ready(function () {
    ko.applyBindings(vm, document.getElementById('singleArea'));
});

And we're done! Refresh your page and you should see a glorious CKEditor, type some content, click save and you should see the JSON of your view model updated with the content from the editor.

Find this post useful? Follow us on Twitter

KnockoutJS

Comments are Locked for this Post