Inline editing with AngularJS

I have written quite a few posts about the latest and greatest of JavaScript - node.js and socket.io are amongst the things that I discussed before. After having a look at my friend's presentation about AngularJS I felt a sudden urge to investigate this (yet another) new technology. From what I heard before, AngularJS is faster in terms of putting together an application and it's very opinionated on how you need to create your application whereas Backbone.js allows you a lot more room to customise your application, and the development time, henceforth, will take much longer.

I hope to create a post in the not so distant future about an application that I have written using JavaScript MVC (well, MV* rather really), but for the time being let's have a look at a very basic usage of AngularJS - that is - inline editing. First of all, please make sure that you have downloaded the AngularJS and inserted it into your HTML file. Once this is done, you can run a quick test by adding the following to your index.html:

<!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>

Which should display: "Check out my calculator! 1 + 2 = 3".

So what do we have here? There a few things to note, first the ng-app directive in the html tag in line 2 which is used to mark an element that Angular should consider to the "root" element of our application. This means that if you don't want your whole code to be part of this directive you can define this attirbute at a later stage, for example as part of a <div> element.

Then we also have the 2x2 curly brackets which is a basic demonstration of AngularJS's templating capability. The double curly brackets tell AngularJS to evaluate the expression inbetween and insert the result into the DOM, replacing the binding. The coolest thing of this is that a binding will result in continuous updates whenever the result of the expression evaluation changes. (Hence making our inline editing possible.)

Let's see how our HTML looks for the 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 result in something similar to the screencapture below. (Note, I'm using the bootstrap CSS library, hence the nice and colourful buttons)

angularjs-firststep

Not very nice right? However this should give you a good idea that we will have 3 elements that we can manipulate - name, role and company, all belonging to the Person object and you can also see the double curly brackets that we discussed earlier. Also please make note of the ng-controller directive. In AngularJS the following MVC components exist:

  • Model — The Model is data in scope properties; scopes are attached to the DOM.
  • View — The template (HTML with data bindings) is rendered into the View.
  • Controller — The ngController directive specifies a Controller class; the class has methods that typically express the business logic behind the application.

Let's add some JavaScript now to bind data to the curly brackets - and we'll create a Profile and Editor objects which will be picked up by the Profile and Editor ng-controller respectively.

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;
}

There's one thing that (should) stand out here, the $scope variable. $scope is nothing more than a data property and the location where the root scope is attached to the DOM is defined by the location of the ng-app directive (in our case, this is the <html> tag).

Using the first function, we are setting up the Profile controller with the person's attributes: name, company and role. We then also create the Editor controller and we add the name, role and company values. If you save your changes and reload the index.html file you should see something similar to this:

Second Step

Our HTML code already allows you to do something awesome, you can click the actual elements. Click on the name, and the <h1> tag gets replaced by an input box:

angularjs-thirdstep

This may need another explanation, editing is possible because of the ng-click and ng-hide directives that you can see inserted into the <h1> and <span> tags. If we click on the <h1> tag, the editable = 'name' action gets called which does two things:

  1. Hides the clicked element via the ng-hide directive: ng-hide="editable == 'name'
  2. Shows the appropriate <span> tag via the ng-show directive: ng-show="editable == 'name'
Please refer back to the HTML code to check out what I'm exactly talking about.

If you go ahead and edit the name field for example, you will notice that nothing much is going to happen - clicking on 'Save' doesn't save the data, however 'Cancel' closes the editor - this is achieved again via the ng-click directive, and we set the 'editable' value to be empty, therefore it won't match any of the ng-show cases.

The final bit of script that we need to add 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 will tell AngularJS to overwrite the previously setup name, company and role values with whatever we type into the input boxes. .name, .company and .role are the names of the appropriate input boxes - for example: <input type="text" size="30" name="name" ng:required ng-model="name">. Again, please refer back to the HTML code above.

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

I hope you liked this overview of AngularJS. Imagine if we could update our profile information on pages such as LinkedIn, Facebook or Google+. I'd like it. A lot.

I hope to produce further articles soon. Until that -- May the Force be with you.

Show Comments