Skip to main content

Inline editing with AngularJS

5 min read

Older Article

This article was published 13 years ago. Some information may be outdated or no longer applicable.

I’ve written quite a few posts about node.js and socket.io before. Then my friend showed me his presentation about AngularJS and I felt the itch to dig into yet another framework. Word on the street was that AngularJS is faster for putting together an application, with strong opinions on how you structure things. Backbone.js, by contrast, gives you more room to customise, which means development takes longer.

I hope to write a post about a full JavaScript MVC (well, MV* really) application soon. For now, let’s look at a basic AngularJS use case: inline editing. First, grab AngularJS and drop it into your HTML file. Then test it with this:

<!DOCTYPE html>
<html ng-app>
  <head>
    <title>AngularJS is awesome</title>
    <script src="/path/to/angular.js"></script>
  </head>
  <body>
    <p>Check out my calculator! 1 + 2 = {{ 1 + 2 }}</p>
  </body>
</html>

That should display: “Check out my calculator! 1 + 2 = 3”.

A few things going on here. The ng-app directive on the html tag marks the “root” element of our application. If you don’t want the whole page under this directive, you can stick it on a <div> instead.

Then there are the double curly brackets. That’s AngularJS templating in action. The brackets tell AngularJS to evaluate the expression inside and inject the result into the DOM. The brilliant part: the binding updates continuously whenever the expression’s value changes. (That’s what makes inline editing possible.)

Here’s the HTML for inline editing:

<!DOCTYPE html>
<html ng-app>
  <head>
    <title>AngularJS is awesome</title>
    <script src="/path/to/angular.js"></script>
    <script>
      //we will add this later
    </script>
  </head>
  <body>
    <div ng-controller="Profile">
      <div ng-controller="Editor">
        <h1
          class="center"
          ng-click="editable = 'name'"
          ng-hide="editable == 'name'"
        >
          {{person.name}}
        </h1>
        <span ng-show="editable == 'name'">
          <form class="form-inline">
            <input
              type="text"
              size="30"
              name="name"
              ng:required
              ng-model="name"
            />
            <button class="btn btn-success" ng-click="save(); editable = ''">
              Ok
            </button>
            <button class="btn btn-warning" ng-click="editable = ''">
              Cancel
            </button>
          </form>
        </span>

        <span ng-click="editable = 'role'" ng-hide="editable == 'role'"
          >{{person.role}} @ </span
        ><span ng-click="editable = 'company'" ng-hide="editable == 'company'"
          >{{person.company}}</span
        >

        <span ng-show="editable == 'role'">
          <form class="form-inline">
            <input
              type="text"
              size="30"
              name="role"
              ng:required
              ng-model="role"
              ng-show="editable == 'role'"
            />
            <button class="btn btn-success" ng:click="save(); editable = ''">
              Ok
            </button>
            <button class="btn btn-warning" ng:click="editable = ''">
              Cancel
            </button>
          </form>
        </span>

        <span ng-show="editable == 'company'">
          <form class="form-inline">
            <input
              type="text"
              size="30"
              name="company"
              ng:required
              ng-model="company"
              ng-show="editable == 'company'"
            />
            <button class="btn btn-success" ng:click="save(); editable = ''">
              Ok
            </button>
            <button class="btn btn-warning" ng:click="editable = ''">
              Cancel
            </button>
          </form>
        </span>
      </div>
    </div>
  </body>
</html>

This should produce something like the screencapture below. (I’m using the Bootstrap CSS library, hence the colourful buttons.)

Not the prettiest thing, right? But you can see we’ve got three editable elements: name, role, and company. They all belong to the Person object, and you can spot the double curly brackets from earlier. Notice the ng-controller directive too. AngularJS uses these MVC components:

  • Model: data in scope properties, attached to the DOM.
  • View: the template (HTML with data bindings) rendered into the view.
  • Controller: the ngController directive specifies a Controller class containing the business logic.

Let’s add some JavaScript to bind data to those curly brackets. We’ll create Profile and Editor objects that map to their respective ng-controller directives:

function Profile($scope) {
  $scope.person = {
    name: 'Tamas Piros',
    company: 'Galactic Empire',
    role: 'Sith Lord',
  };
}

function Editor($scope) {
  $scope.name = $scope.person.name;
  $scope.role = $scope.person.role;
  $scope.company = $scope.person.company;
}

One thing stands out here: the $scope variable. $scope is just a data property. The root scope attaches to the DOM wherever the ng-app directive sits (in our case, the <html> tag).

The first function sets up the Profile controller with the person’s attributes: name, company, and role. The second creates the Editor controller and copies those values across. Save your changes and reload. You should see something like this:

The HTML already lets you do something great. Click the name, and the <h1> tag swaps out for an input box.

Here’s what’s happening. Editing works because of the ng-click and ng-hide directives on the <h1> and <span> tags. Click the <h1> tag, and editable = 'name' fires, doing two things:

  1. Hides the clicked element via ng-hide: ng-hide="editable == 'name'
  2. Shows the matching <span> via ng-show: ng-show="editable == 'name'

Refer back to the HTML to see this in context.

If you edit the name field and click ‘Save’, nothing happens yet. ‘Cancel’ does close the editor though, thanks to ng-click setting ‘editable’ to empty, which doesn’t match any ng-show condition.

The last piece is the save function. Add this after the Editor function:

$scope.save = function () {
  $scope.person.name = $scope.name;
  $scope.person.company = $scope.company;
  $scope.person.role = $scope.role;
};

This tells AngularJS to overwrite the name, company, and role values with whatever’s in the input boxes. .name, .company, and .role match the input box names, e.g.: <input type="text" size="30" name="name" ng:required ng-model="name">. Check the HTML above for reference.

Once you’ve added all the JavaScript, you should be able to edit all three values on the page and save them.

I hope you liked this overview of AngularJS. Imagine editing your profile information on LinkedIn, Facebook, or Google+ this way. I’d like that. A lot.