Skip to content

13 Rich text editing

Dave Strus edited this page Aug 13, 2015 · 1 revision

A simple <textarea> is a little limiting for the kind of semi-rich notes we want to create.

Let's add a JavaScript richtext editor!

After a little Googling, we found textAngular, which looks nice and works with Angular. Rich text editors usually replace the contents of a textarea with a new element with certain behaviors, so it's important to check for Angular compatibility. We tried using wysihtml5-bootstrap, but the AngularJS binding didn't work and instead showed up as the literal text string {{ note.body_html }}. We could update wysihtml5-bootstrap to be compatible, but using textAngular give us an opportunity to look at custom html elements with Angular.

bower.json

    "font-awesome": "4.4.x",
    "textAngular": "1.4.x"

We specified version 1.4.x since that's the latest according to the README on GitHub as of this writing. Run npm install and you should see something like this:

textAngular#1.4.3 app/bower_components/textAngular
├── angular#1.4.3
├── font-awesome#4.4.0
└── rangy#1.3.0

That means it installed version 1.4.3 into app/bower_components/textAngular.

This also installed some dependencies to textAngular, amd we need to find their paths under app/bower_components and include them in our HTML document.

To find out what exactly we need to specify, and in what order, let's look at the documentation here on GitHub.

We'll need to remove the leading slash from the examples, since we are using a relative path to bower_components. So this should work:

app/index.html

...
  <!-- just after font-awesome in the <head> -->
  <link rel="stylesheet" href="bower_components/textAngular/src/textAngular.css">

  <!-- just before closing </body> tag -->
  <script src="bower_components/textAngular/dist/textAngular-rangy.min.js"></script>
  <script src="bower_components/textAngular/dist/textAngular-sanitize.min.js"></script>
  <script src="bower_components/textAngular/dist/textAngular.min.js"></script>

We also need to replace the <textarea> tag with the special <text-angular> tag as also shown on the README.

app/views/notes.html

<text-angular name="body_html" ng-model="note.body_html" placeholder="Just start typing..."></text-angular>

We also need to inject the dependency to textAngular to our module. This mixes in the behavior to transform the non-standard HTML <text-angular> tag. AngularJS will replace this with a <textarea> that works the way the textAngular javascript library sets it up, with the two-way data binding we know and love.

app/notes/notes.js

var noteApp = angular.module('notely.notes', ['ngRoute', 'textAngular']);

If we reload the page, hopefully we'll see a nice row of buttons to make things bold or underlined or change font sizes, etc. If you click notes in the sidebar, you'll see that our bindings remain intact.

If you haven't already get rid of that gray well around the form, do it now.

app/index.html

<main>
  <!-- BEGIN main content -->
  <div ng-view></div>
  <!-- END main content -->
</main>

That looks pretty nice. The flat look is so hot right now.

Let's customize the toolbar, since we don't want or need all those things. If you check out textAngular's wiki, you'll see that the buttons are customizable. So let's strip that toolbar down to just the essentials.

_app/notes/index.html

    <text-angular
      name="body_html"
      ng-model="note.body_html"
      ta-toolbar="[
        ['bold', 'italics', 'underline'],
        ['ul', 'ol', 'indent', 'outdent'],
        ['html'],
        ['insertLink']]"
      placeholder="Just start typing..."></text-angular>

Now we have a much nicer toolbar, but we could use a little bit of space between the toolbar and the textarea. Let's add a little bit of css to our stylesheet.

app/app.css

.ta-editor {
  margin-top: 0.5em; }

Much better. Try it out with some new and existing notes, and make sure everything is working.

We could display the HTML version of the note in the sidebar by adding the ta-bind directive, and then binding to note.body_html instead of note.body_text. Here's what that would look like:

<div class="note-body" ta-bind ng-model="note.body_html"></div>

You might prefer to leave it as plain text in the sidebar. Do whichever you like.

Regardless, let's commit.