Last month I did an interview with the Adventures in Angular podcast crew, you can listen here.
I also did a talk at the AngularJS Meetup in Oslo. You can watch the recoding here.
Both the podcast and the Meetup talks were loosely centered around using the next version of JavaScript with the current version of Angular.
In addition to all the syntax sugar in ES6, which makes JavaScript code more expressive, the new class keyword works well for building services and controllers in Angular. As an example, imagine you are building a Pong game, and need a service to control the left paddle and a second service for the right paddle. One paddle is controlled by the keyboard, the other by AI. This is a scenario where you might, if you are brave, consider inheritance, as long as the relationship stays simple.
(function(app) { class Paddle { constructor() { this.x = 0; this.y = 0; } startMoveDown() { this.y += 2; } stopMoveDown() { this.y -= 1; } startMoveUp() { this.y -= 2; } stopMoveUp() { this.y += 1; } } class LeftPaddle extends Paddle { constructor(keyboardHandler) { Paddle.call(this); this.x = 25; this.y = 100; keyboardHandler.onArrowUp(38, () => this.startMoveUp(), this.stopMoveUp()); keyboardHandler.onArrowDown(40, () => this.startMoveDown(), this.stopMoveDown()); } } class RightPaddle extends Paddle { constructor() { Paddle.call(this); this.x = 975; this.y = 300; } } app.service("leftPaddle", LeftPaddle); app.service("rightPaddle", RightPaddle); }(angular.module("pong")));
The class constructor for controllers and services will be injectable, but you’ll want to use module.service to register service classes, and not module.factory, because only .service instantiates the service using new.
Neil Young once sang how “every wave is new until it breaks”. The line was a poke at trendiness in the music industry, but I find the lyrical snippet is applicable to software development, too, in a number of subtle ways.
There has been a lot of turmoil surrounding the future direction of Angular, which is fair. The preview and announcements made for Angular 2.0 during ng-europe were dramatic and conveyed no empathy for the customers and development teams who have taken a dependency on the framework. Those people are left wondering when the ng-wave will break.
Web developers have always faced incompatibilities, but have also been fortunate enough to build software on top of a set of technologies and standards that have diligently preserved backward compatibility. This diligence allows the nearly 20 year old web page for the animated movie Space Jam to live on. We’ve been accustomed to building software using web standards that keep working into the future. Stability is good for business.
But backward compatibility has a price. I believe the web moves at a snails pace, which is contrary to popular opinion. However, compare the evolution of the JavaScript language to some of its peers like C# or even Java. Next year’s ECMASCript 6 release is the first big move forward for the language in nearly 20 years. Also consider the XMLHttpRequest API. The API is central to today’s applications, but it has taken the industry 15 years to standardize the API and build the tools to make mainstream developers productive with asynchronous requests and dynamic DOM updates.
Should Angular 2.0 be backward compatible? Or should Angular 2.0 follow Py3k?
Python 3.0, also known as “Python 3000” or “Py3K”, is the first ever intentionally backwards incompatible Python release. There are more changes than in a typical release, and more that are important for all Python users. Nevertheless, after digesting the changes, you’ll find that Python really hasn’t changed all that much – by and large, we’re mostly fixing well-known annoyances and warts, and removing a lot of old cruft.
Web development feels like a fast changing environment, but a closer look will show we mostly churn in the turbulence of small, incremental improvements. It’s rare for a wave to arrive and move everyone forward.
I still believe Angular 1.x is the best wave to ride today. I already have applications in production with Angular 1.2, and at least one more on the way with 1.3. With the core Angular code base being only 25k lines of JSDoc’ed, tested, working, healthy code, I believe the wave can keep rolling for years to come.
I also believe Angular 2.0 should be a new wave that makes a break from Angular 1.x and evolves without being encumbered by backward compatibility or designs for an easy migration path. We’re still early in the history of application development on the web, and there will one day be a newer, bigger, better swell. It’s name might be Angular 2, or maybe something entirely new will come along. That’s life in the rough seas of web development, where you can either fight the waves and drown, or surf the waves and stay on top.
There are a few points in “AngularJS: The Bad Parts” I’d be happy to debate, but let’s focus on “Bad Idea #4”, talking about controller constructor functions:
That’s right, these constructors never create new instances. They are “applied” to a scope object.
Let’s use the following example. A simple controller that is setup to use controller as syntax from the view.
var module = angular.module("app", []); var MainController = function() { this.message = "Hello"; this.changeMessage = function() { this.message = "Bonjour!"; }; this.isMainController = function(object) { return object instanceof MainController; }; this.isObject = function(object) { return object instanceof Object; }; }; module.controller("MainController", MainController);
If we place the following markup in a view:
<div> {{ main.isMainController(main) }} {{ main.isObject(main) }} </div>
.. we’ll see the output true and true. The first true is a good indication that Angular does use the controller function as a constructor function, in other words, Angular invokes the function using the new keyword. In fact, we can even rewrite a controller using the everyday constructor function and prototype object approach of JavaScript, and everything just works.
var MainController = function() { this.message = "Hello"; }; MainController.prototype = { changeMessage: function() { this.message = "Bonjour!"; }, isMainController: function(object) { return object instanceof MainController; }, isObject: function(object) { return object instanceof Object; } };
The above is actually a good example of why I like working with Angular. You can write plain, simple JavaScript objects using established conventions and terminology, then plug the objects into Angular to achieve a goal. There is no magic required or intrusions from the framework. You can even start writing controllers using ES 6 class syntax, but that’s a topic for a future post.
In a previous post we looked at the new class keyword in JavaScript.
We’ve always had the ability to create objects in JavaScript, and give these objects data to hold and methods to call. In fact, we could have written an “employee” object using a simple object literal instead of a class.
let developer = { name: "Scott", doWork: function() { return `${this._name} is working`; }, get name() { return this._name.toUpperCase(); }, set name(newName) { if(newName) { this._name = newName; } } }; expect(developer.name).toBe("SCOTT"); developer.name = "Alex"; expect(developer.doWork()).toBe("Alex is working");
The advantage to having a class is how we can create multiple developers just by using the new keyword and not have to write out an entire literal definition like the above code. Each object is unique and contains its own data, but the method implementations are consistent and shared.
let dev1 = new Employee("Scott"); let dev2 = new Employee("Alex");
In fact, even before the class keyword came along, we had the ability to define a blueprint for object construction in JavaScript. The approach was one we called the “constructor function and prototype object” approach.
let Employee = function(name) { this._name = name; }; Employee.prototype = { doWork: function() { return `${this._name} is working`; }, get name() { return this._name.toUpperCase(); }, set name(newName) { if(newName) { this._name = newName; } } }; let developer = new Employee("Scott"); expect(developer.name).toBe("SCOTT");
As it turns out, all the class keyword is doing behind the scenes is setting up a constructor function and prototype object. This means all of the tricks we’ve learned in the past still work. For example, “borrowing” a method from a prototype object:
class A { doWork() { return "complete!"; } } var result = A.prototype.doWork.call(); expect(result).toBe("complete!");
The instanceof operator also works as expected.
class A { // … } var a = new A(); expect(a instanceof A).toBe(true); expect(a instanceof Object).toBe(true);
You can also still augment all instances of a type by modifying prototype objects (if you like to live dangerously).
class A { } A.prototype.newMethod = function() { return "new!"; }; var a = new A(); expect(a.newMethod()).toBe("new!");
You can think of the class keyword as being syntactic sugar for creating constructor functions and prototype objects. However, there is more to the class keyword than what we’ve seen so far. We’ll look at class inheritance in the next post.
In a previous post we looked at a custom validation directive to confirm a user’s password.
The bigger picture from the post was not about how to register a user for a website, but how to work with the new validation and validation message features introduced in Angular 1.3, which just fully released this week.
Before we take a step back and look in more detail at what’s new in 1.3, let’s review what stays the same when it comes to form validation.
Here are a few points about what has not changed with validation.
1. When you give a <form> a name, Angular will add a property with the same name to the current $scope.
2. All named inputs inside a named <form> will be added to the form’s named property in $scope.
3. Each form and input still have boolean properties to describe if the object is $pristine or $dirty, and $valid or $invalid.
4. Angular still adds CSS classes to each form and input describing the state of the object (ng-dirty, ng-pristine, ng-valid, ng-invalid).
5. There is still an $error property on each form and input. The $error property describes failed validations.
Thanks to the behavior described in the above points, you can have a relatively functional form just using the following markup:
<form name="profileForm" ng-submit="profile.submit(profileForm.$valid)" novalidate> <input type="number" name="favoriteNumber" ng-model="profile.number" required min="1" /> <input type="submit" value="Save" /> </form>
.. and a little bit of CSS ..
.ng-invalid { border-color: red; border-width: 2px; }
You can try the above code on Plunker.
Angular 1.3 introduces a number of new features for form validation, including a new approach to writing validation code, a new approach to showing validation error messages, and plenty of small enhancements. like adding ng-submitted as a class to a form after a submit event. To only show validation errors or color code erroneous inputs after the user presses the submit button now only requires a more specific selector in CSS.
form.ng-submitted .ng-invalid { border-color: red; border-width: 2px; }
Try the updated plunk here.
What follows is some more detail about validation messages and the validation API.
One of the messier parts of forms with Angular was the display management of validation errors. The management usually involved ng-if or ng-show directives with ugly expressions like in the following code.
<input type="number" name="favoriteNumber" ng-model="profile.number" required min="1" /> <span ng-if="profileForm.favoriteNumber.$error.required"> Required! </span>
And this is only a single validation error for a single field. Once you added messages for each validation attribute in each input field, then added class names, there was quite a bit of markup.
ngMessages is a new module for Angular that your application can depend on after adding angular-message.js. Once in place, validation messages look like the following.
<input type="number" name="favoriteNumber" ng-model="profile.number" required min="1" /> <div ng-messages="profileForm.favoriteNumber.$error" class="errors"> <span ng-message="required">Required!</span> <span ng-message="min">Too small!</span> </div>
The ngMessages directive will watch the $error property of an input and toggle the first matching ngMessage directive in its messages collection.
Now we’ve gotten most of the uglier expressions out of the markup, but we can also define a template file for messages..
<span ng-message="required">Required!</span> <span ng-message="min">Too small!</span> <span ng-message="number">Must be a number!</span> <span ng-message="odd">Odd numbers only!</span> <!-- and so on, for all possible validation attributes -->
.. and include the template whenever we need to show error messages for a field.
<div ng-messages="profileForm.favoriteNumber.$error" ng-messages-include="messages.html" class="errors"> </div>
Now we’ve removed most of the unsightly and bulky markup from our forms. However, since error messages come from a template they are likely to be generic error messages like the ones in this example, messages like “Too small!”. There is no easy way to poke a field name or attribute value into a message, unfortunately, but there is the ability to override a message.
<div ng-messages="profileForm.favoriteNumber.$error" ng-messages-include="messages.html" class="errors"> <!-- overrides the min message from the include --> <span ng-message="min">Must be more than 1</span> </div>
This last bit of code added to the Plunker here.
Also new in 1.3 is the $validators object on the ngModel controller. Adding a property to this object effectively registers a new validation rule to an input using the name of the property. To get to the $validators property you’ll want to create a custom directive that requires the ngModel controller. The following code adds an “odd” validation rule that I can use to ensure that an input type=”number” will only accept odd numbers.
app.directive("odd", function() { return { restrict: "A", require: "ngModel", link: function(scope, element, attributes, ngModel) { ngModel.$validators.odd = function(modelValue) { return modelValue % 2 === 1; } } }; });
Angular automatically invokes the odd function whenever the model value changes (you can also receive the view value as a second parameter)., All the validation function needs to do is return true or false – is the value valid? A return of false will mark the model as invalid and set a property on the associated $error object. To apply the validation rule use the directive on an element using ngModel.
<input type="number" name="favoriteNumber" ng-model="profile.number" required min="1" odd />
The associated ngMessage for the attribute will automatically appear when the validation rule fails.
<span ng-message="odd">Odd numbers only!</span>
An updated plunk using the above code lives here.
A validation rule added to a model’s $asyncValidator pipeline will typically be a validation rule that needs server-side logic to make a decision. Like everything and anything async in Angular, an async validator will return a promise. If the promise resolves, Angular considers the value valid. If the promise is rejected, the value is invalid.
Here is a prime number validation rule that simulates a slow server-side response using $timeout.
app.directive("prime", function($q, $timeout) { var isPrime = function(n) { if (n < 2) { return false; } for (var i = 2; i <= Math.sqrt(n); i++) { if (n % i == 0) { return false; } } return true; }; return { restrict: "A", require: "ngModel", link: function(scope, element, attributes, ngModel) { ngModel.$asyncValidators.prime = function(modelValue) { var defer = $q.defer(); $timeout(function(){ if(isPrime(modelValue)) { defer.resolve(); } else { defer.reject(); } }, 2000); return defer.promise; } } }; });
Using an async validator is no more difficult than using a regular validator, all we need to do is add the directive to the input element.
<input type="number" name="favoriteNumber" ng-model="profile.number" required min="1" odd prime /> <div ng-if="profileForm.favoriteNumber.$pending"> Calculating.... </div>
Notice you can give some visual clues a pending validation calculation by using the $pending flag provided by Angular.
Try this version of the code in this plunk.
The summary for this article is intentionally left blank. Like you were going to read it anyway…
Historically, many developers learn JavaScript after learning languages like C++, Java, C#, Ruby, or Python. All of these languages have a class keyword, and in many of these languages, the class keyword is the primary building block for constructing software.
In modern times, many developers learn JavaScript as a first language, so the new class keyword in ES6 will be a brand new tool.
Regardless of a developer’s background, the class keyword in JavaScript will play a role similar to the class keyword in other languages. Classes allow developers to define a blueprint for constructing objects. Each object a program creates from the class blueprint will be an object with the same methods and placeholders for data specific to each object.
We’ve always had the capability of building object with data and behavior in JavaScript, but like other ES6 features, the class keyword makes the common practice both succinct and more explicit.
Every class has a name, and a body containing the method definitions for the class.
class Employee { hire() { this.hired = true; } getStatus() { if(this.hired) { return "hired"; } } }
The above class has two methods: hire and getStatus. Notice we do not need to use the function keyword to define the methods. These methods will be available on every object we create using Employee, and as you can see in the implementation, these methods can save and retrieve state inside the object using the this keyword.
We create Employee objects using the new keyword.
let developer = new Employee(); developer.hire(); expect(developer.hired).toBe(true); expect(developer.getStatus()).toBe("hired");
Quite often you’ll want an object to initialize itself with specific data right from the start. We can add this initialization logic using a constructor.
Every class may specify a constructor. The runtime will invoke the constructor when instantiating a class, and we can use the constructor to initialize state in an object, often by accepting parameters in the constructor method.
class Employee { constructor(name) { this.name = name; } getName() { return this.name.toUpperCase(); } } let developer = new Employee("Scott"); expect(developer.name).toBe("Scott"); expect(developer.getName()).toBe("SCOTT");
A class can also define a property with get and set to encapsulate a field.
class Employee { constructor(name) { this._name = name; } doWork() { return `${this._name} is working`; } get name() { return this._name.toUpperCase(); } set name(newName){ if(newName){ this._name = newName; } } } let developer = new Employee("Scott"); expect(developer.name).toBe("SCOTT"); developer.name = "Alex"; expect(developer.doWork()).toBe("Alex is working");
ES6 also supports class inheritance and interaction between a class and the class superclass. We’ll take a look at these features in the next installment of the series.
Form validation and custom validation directives are relatively easy with the changes in Angular 1.3. Try the sample plunk here.
Let’s look at the scenario where we need to confirm a new user’s password during registration. Registration is not so common in this day and age of federated identity, but is still a useful example and a frequent requirement.
We could put logic into a model to confirm a password, but it is probably better to separate the logic into a reusable directive. AngularJS already provides directives for the standard HTML validation attributes like required. All we need to do is follow a similar pattern.
1. Require the ngModel controller.
2. Add a method to the ngModel controller’s $validators object. Angular will invoke the function when the model value changes. The function returns a boolean, and a return value of false will set the corresponding ngModel’s $error property automatically.
The compare-to directive looks like the following:
var compareTo = function() { return { require: "ngModel", scope: { otherModelValue: "=compareTo" }, link: function(scope, element, attributes, ngModel) { ngModel.$validators.compareTo = function(modelValue) { return modelValue == scope.otherModelValue; }; scope.$watch("otherModelValue", function() { ngModel.$validate(); }); } }; }; module.directive("compareTo", compareTo);
You can use the directive inside of markup like so:
<input type="password" name="confirmPassword" ng-model="registration.user.confirmPassword" required compare-to="registration.user.password" /> <div ng-messages="registrationForm.confirmPassword.$error" ng-messages-include="messages.html"></div>
The ng-messages directives, also new in 1.3, makes it easy to provide common error messages for form inputs. You can also see them at work in the plunk.