H

May 29, 2015

I'm working on a CMS built with AngularJS backed by ZF2 & MySQL. One of the requirements is to have a WYSIWYG editor implemented on some of the fields where formatted text is a must-have.

Most developers would jump right to TinyMCE or some other popular WYSIWYG. Since HTML in the hands of non-developers is terrifying, I opted to utilize markdown to avoid broken tags or insane proprietary Microsoft markup.

I decided on bootstrap-markdown, which yes has a dependency on Bootstrap—luckily I'm already including Bootstrap.

So let's stick this into a directive:

app.directive('markdownField', ['$parse', function(parse) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            // We use $parse to avoid hardcoding a scope attribute here.
            var setter = parse(attrs.ngModel).assign;

            // Only initialize the $.markdown plugin once.
            if (! element.hasClass('processed')) {
                element.addClass('processed');

                // Setup the markdown WYSIWYG.
                element.markdown({
                    autofocus: false,
                    saveable: false,
                    iconlibrary: 'fa',
                    onChange: function(event) {
                        // When a change occurs, we need to update scope incase
                        // the user clicked one of the plugin buttons (which 
                        // isn't the same as a keydown event that angular would
                        // listen for).
                        setter(scope, event.getContent());
                    }
                });
            }
        }
    };
}]);

Be sure to include that onChange event handler, as the comment states: if a change in the input or textarea value is modified by clicking one of the plugin buttons (bold, italic, etc.), then Angular won't pick up that change—which depending on your situation may be important or not.

Next up: Avoid Abbreviating

Proceed