Editable HTML element with AngularJS and HTML5 contentEditable attribute

      3 min read     

There is a new attribute in HTML5 „contentEditable”. It allows user to edit content of the website elements like „span” or „div”. It might be very useful when you need to make some element editable only in the specific circumstances.

In my TaskRoo project I am using „contentEditable” with AngularJS to make tasks names editable in-place with the double-click.

ContentEdit

In this post I will describe how to implement and use AngularJS directive to make HTML element editable in-place. In case you are just looking for solution, you can find complete implementation on plunker:

http://plnkr.co/edit/Yt4bFd9mF9iwZirtWvYg?p=preview

Lets start with HTML:

<!DOCTYPE html>
<html>

  <head>
    <script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script data-require="angular.js@1.3.5" data-semver="1.3.5" src="https://code.angularjs.org/1.3.5/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="aetasApp" ng-controller="AetasCtrl">
    <h1>Editable content - AngularJS</h1>
    <p>
      <a href="http://aetas.pl">http://aetas.pl</a>
    </p>
    <span quick-edit ng-model="someObj.someValue" ng-change="save(someObj)"></span>
  </body>

</html>

Nothing fancy here. JQuery and AngularJS libraries are included.

You can spot the „span” tag with „quick-edit”, „ng-model” and „ng-change” attributes. This „span” element we will make editable on double click.

Tags „ng-model” and „ng-change” are basic Angular directives. Ng-model binds „span” tag to a property on the scope. In our case it is bound to „someObj.someValue” which we will later create in JavaScript. Ng-change evaluates the given expression when the user changes the input. In this case, it will call „save” function in JS with „someObj” also taken from JS.

The important bit here is „quick-edit” which is our directive implemented in the JavaScript below.

So, now JavaScript code with explanation in the comments:

// Code goes here

var app = angular.module("aetasApp", []);

app.controller("AetasCtrl", function($scope) {
  // object with the value displayed in the HTML editable field
  $scope.someObj = {
    someValue: "This is editable value. Double click to edit..."
  };
  
  // this function will be called with ng-change
  // put here whatever you want to do with the changed object
  $scope.save = function(updatedObject) {
    console.log("This is new value: "+ updatedObject.someValue);
    alert(updatedObject.someValue);
  };
});

// main directive
app.directive("quickEdit", function() {
    return {
        restrict: 'A',
        require: "?ngModel", // require ngModel on the same HTML element as quickEdit
        link: function(scope, element, attrs, ngModel) {
            ngModel.$render = function() {
                element.text(ngModel.$viewValue || '');
            };


            // add HTML5 "contentEditable" attribute with value "true" on double click
            // this will make field editable
            element.dblclick(function() {
                $(this).attr("contentEditable", "true");
                $(this).focus();
            });

            // handling "return/enter" and "escape" key press
            element.bind('keydown', function(event) {
                var keycode = (event.keyCode ? event.keyCode : event.which);
                // on "enter" set "contentEditable" to "false" to make field not-editable again
                // and call "read" method which is responsible for setting new value to the object in ngModel
                if (keycode === 13) { // ENTER
                    $(this).attr("contentEditable", "false");
                    $(this).blur();
                    event.preventDefault();
                    read();
                }
                // on "escape"and set the text in the element back to the original value
                // and set "contentEditable" to "false" to make field not-editable again
                if (keycode === 27) { // ESCAPE
                    element.text(ngModel.$viewValue);
                    $(this).attr("contentEditable", "false");
                    $(this).blur();
                }
            });

            // this is called to update the value in the object after edit
            function read() {
                var text = element.text();
                ngModel.$setViewValue(text);
            }
        }
    };
});

That’s it. Just replace „someObj” and „save” function with whatever you need.

Try it working in plunkr.

comments powered by Disqus