The last feature I need to add for the video sample is the ability to edit and delete videos. One approach with Angular is to bind edit and delete button click events to the model using the ng-click click directive, which we've seen before.
<tr ng-repeat="video in videos"> <td>{{video.Title}}</td> <td>{{video.Length}}</td> <td> <button ng-click="editVideo(video.Id)">Edit</button> <button ng-click="deleteVideo(video.Id)">Delete</button> </td> </tr>
What's new in the two usages of ng-click here is the complexity of the expression inside. More on expressions later, but ultimately the expression will invoke delete and edit methods with parameters, where the delete method can look like the following:
$scope.deleteVideo = function (id) { $http.delete(serviceUrl + "/" + id) .success(function () { $scope.videos = _.reject($scope.videos, videoFinder(id)); }); };
This code is using Underscore's reject to help update the model.
All the HTML and JavaScript for the sample is in a gist, and if you followed (closely) the original course at Pluralsight, you might remember the original sample was around 120 lines of script with jQuery and Handlebars. The same features in Angular require around 60 lines of script. However, we've only scratched the surface of what we can do with AnjularJS. Not only can we write less code, we can add some new features using additional Angular APIs, and still have a testable controller.
We'll look at some of these additional features in the future. For now I wanted to return to the ng-click expressions.
At first glance, ng-click looks similar to writing JavaScript code inside an onclick attribute, which we've learned to avoid for many good reasons. However, the resemblance is only superficial. An ng-click directive doesn't prevent progressive enhancement or go against the true spirit of unobtrusive JavaScript. I think of ng directives and other {{expressions}} as natural extensions to the declarative language of HTML. Angular uses a compiler service at runtime to process the directives and construct linkages between the HTML view and a model.
Another significant difference between ng-click and onclick is the execution context. Code inside an onclick attribute executes against the global window object, while an expression inside of ng-click executes against a specific scope object, typically the scope object representing the model for the current controller.
In other words, if you wanted to invoke the global alert function in JavaScript, the following onclick handler will work:
<button onclick="alert('hello!')">Say Hi</button>
However, the following ng-click code will not invoke the global alert function:
<button ng-click="alert('hello!')">Say Hi</button>
The only way for the code inside the directive above to work is to have an alert method defined for the current scope.
$scope.alert = function(message) { $window.alert(message); };
In this example we'll forward the call to the global alert function by using a well known $window service that is injected into the controller (which is a testable approach to using the window object).
The code in the ng-click attribute for the edit and delete buttons actually executes against a scope defined by the ng-repeat directive. The ng-repeat directive is providing a video for every object in the videos collection, and the repeat scope prototypically inherits from the controller scope (which is why both deleteVideo from the controller scope and video.Id from the repeat scope are available to use in the expression). For more details on how scopes in Angular work, see "The Nuances of Scope Prototypal Inheritance". Scopes are important to understand.
One final difference between ng-click and onclick is that the expression syntax supported by ng-click is like a subset of JavaScript. You can make method calls, use a ! operator, and even perform an assignment (which is frowned upon), but you cannot use flow control statements, among other things. Remember the view is supposed to be simple, so expressions typically reference a property or invoke a method to keep most of the logic inside a controller.
Continuing to reach for feature parity with my original jQuery with ASP.NET Web API sample, I need to have the ability to create a new video.
The original sample caught the form submit event and serialized form data for an AJAX submission to the web server.
With AngularJS I only need to bind some form elements to the model (using the ng-model directive), and bind a click event (with the ng-click directive).
<form> <input type="hidden" ng-model="editableVideo.Id"/> <label>Title:</label> <input type="text" ng-model="editableVideo.Title" required /> <label>Length</label> <input type="number" ng-model="editableVideo.Length" min="1" max="360" /> <input type="submit" value="Save" ng-click="saveVideo()" /> </form>
Note there is also an ngSubmit directive, but Angular will prevent the default form submission if I have only one or the other. When the user clicks save, I just need to post the new video information to the Web API. The controller code now looks like the following:
var VideoController = function ($scope, $http) { var serviceUrl = "/api/videos"; var blankVideo = { Id: "", Title: "", Length: 75 }; var refreshVideos = function() { $http.get(serviceUrl).success(function (data) { $scope.videos = data; }); }; $scope.isEditVisible = false; $scope.showEdit = function () { $scope.isEditVisible = true; $scope.editableVideo = angular.copy(blankVideo); }; $scope.saveVideo = function() { $scope.isEditVisible = false; $http.post(serviceUrl, $scope.editableVideo) .success(function (video) { $scope.videos.push(video); }); }; refreshVideos(); };
Notice it is easy to keep private methods and data inside a controller.
Next I need the ability to delete and edit existing videos, and then the sample will behave exactly like the original "jQuery only" sample. We'll look at those scenarios next.
One of the nicer features of Angular is the framework's ability to separate the roles of the model, the view, and the controller. The separation is clean enough that you shouldn't need to manipulate the DOM directly from code inside the controller. Instead, the controller only manipulates the model, which influences the view through data bindings and directives. The end result is a clean and testable.
In the last post we saw how to build a simple tabular display with Angular and the Web API, but in my original non-Angular sample I also had a "Create Video" button that would open a form with inputs for the user to enter new video information. This was all achieved using jQuery to wire up click event handlers and using jQuery to find DOM elements by ID, then using jQuery to toggle visibility. With AngularJS none of the jQuery code is needed.
Let's add the following HTML inside the ng-app div from the previous post:
<button ng-click="showEdit">Create Video</button> <div ng-show="isEditVisible"> <hr /> <form> <input type="hidden" name="id" value =""/> <label for="title">Title:</label> <input type="text" name="Title" value="" /> <!-- more inputs... --> </form> </div>
Pay no attention to what is inside the form just yet. The focus of this post is the ng-click and ng-show directives. Directives in Angular are programmable components that can perform specific tasks to make the application more declarative and easy to maintain and test.
The ng-click directive, as you might suspect, is a directive containing an expression for Angular to evaluate against the current controller scope when the user clicks the button. The ng-show directive contains an expression that will determine the visibility of an element. If isEditVisible is truthy the element will be visible, if falsy the element will dissapear. There is also an ng-class directive to set CSS classes on an element, so these directives help you stay "hands off" the DOM from a controller. There are additional directives available, and you can always plug in custom directives.
With the HTML in place, we only need a few lines of code in the controller to hide the form on load, and show the form when a user clicks the button.
var VideoController = function ($scope, $http) { $scope.isEditVisible = false; $scope.showEdit = function () { $scope.isEditVisible = true; }; $http.get('/api/videos/').success(function (data) { $scope.videos = data; }); };
Fans of XAML and the MVVM pattern might see some similarities in how Angular's MVC approach works. One significant difference to me is the clean markup compared to XAML. I always felt bad when I saw the ceremony of {Bindingicus Pathius=isEditVisible , Converteralicus={StaticusResourcious visibilityFromBool}} in XAML.
In my MVC 4 Fundamentals video I have a section using the ASP.NET Web API on the server with jQuery and Handlebars on the client to build a somewhat interactive UI. A few people have asked what the code would look like with AngularJS.
The first part of the example, display a list of videos, is easy with Angular. Here is the HTML:
<div ng-app ng-controller="VideoController"> <table> <thead> <th>Title</th> <th>Length</th> <th></th> </thead> <tbody> <tr data-id="{{video.Id}}" ng-repeat="video in videos"> <td>{{video.Title}}</td> <td>{{video.Length}}</td> <td> <button class="editVideo">Edit</button> <button class="deleteVideo">Delete</button> </td> </tr> </tbody> </table> </div>
The ng-app directive represents the application "root" for angular. Most applications would have ng-app on the body element, or the top html element, but you can also root the application further into the DOM. The ng-controller directive provides the name of a controller function for Angular to find and invoke. The controller provides the model and allows us to use data binding in between the model and the view (the HTML).
The controller function looks like this:
var VideoController = function($scope,$http) { $http.get('/api/videos/').success(function(data) { $scope.videos = data; }); };
Angular will inject the $scope and $http parameters into the controller (names are significant). $scope is where we can place the model, while $http is a service that provides low-level HTTP communication (we'll see a higher level service in a later post). The above code is calling a Web API controller on the server to retrieve a list of videos, and placing them into the $scope when the call is successful. Back in the HTML, an ng-repeater will loop through the videos when they become available (Angular knows when the model changes), and outputs table rows with video information (via {{ }} templates).
The above is a quick demonstration of why I like Angular. It's quick, clean, and easy to learn. In my original demo I also inserted, deleted, and edited videos. We'll take a look at these scenarios next.
The Kata repository has new additions.
The Refactoring kata I pushed out last year now has a Java version available (thanks, Tom!).
Related to the previous post, I also added a Composition Kata. Excerpt from the README:
One day a developer was writing some logic to perform calculations on a collection of Measurement objects with X and Y properties. The developer knew the business would need different types of aggregations performed on the collection (sometimes a simple sum, sometimes an average), and the business would also want to filter measures (sometimes removing low values, sometimes removing high values).
The developer wanted to make sure all algorithms for calculating a result would filter a collection of measurements before aggregation. After consulting with a book on design patterns, the developer decided the Template Method pattern would be
ideal for enforcing a certain ordering on operations while still allowing subclasses to override and change the actual filtering and the calculations.
public abstract class PointsAggregator { protected PointsAggregator(IEnumerable<Measurement> measurements) { Measurements = measurements; } public virtual Measurement Aggregate() { var measurements = Measurements; measurements = FilterMeasurements(measurements); return AggregateMeasurements(measurements); } protected abstract IEnumerable<Measurement> FilterMeasurements(IEnumerable<Measurement> measurements); protected abstract Measurement AggregateMeasurements(IEnumerable<Measurement> measurements); protected readonly IEnumerable<Measurement> Measurements; }
From this base class the developer started creating different classes to represent different calculations (along with unit tests).
Your job is to create a new calculation. A calculation to filter out measurements with low values and then sum the X and Y values of the remaining measurements. You'll find details in the comments of the code, and the unit tests.
You'll implement the calculation twice. Once by building on top of the Template Method approach (in the Inheritance folder), and once with a compositional approach (in the Composition folder). When you are finished and all of the tests pass (9 total, you'll start with 6), take some time to reflect on the different approaches.
- Which are the drawbacks and benefits to each?
- Which one would you rather build on in the future?
It was about 12 years ago when I helped to write an application that featured a class hierarchy like the following:
I remember the code because I was the one to refactor the application to build the class hierarchy in an attempt to remove duplicated code.
I believed what I was creating was a better application.
What I actually created was a model where other developers struggled to understand when a virtual method override would kick in. They had to work hard to figure out when to properly call a base class method. All changes inside the hierarchy were like moving balanced blocks of wood in a game of Jenga. Someone eventually has to lose a game of Jenga. You just hope the structure stays stable enough to make it through through your turn.
As a kid my parents told me not to play with matches, not to go near the dog chained to the oak tree down the street, and to always hold on to the handrail when the back porch steps were wet.
As a kid, I didn't understand why my parents told me these things until I was burned, or chewed, or contemplating life during a cartwheeling descent of rain slickened steps.
Similarly, I believe there are some aspects of software development that you have to experience to truly appreciate. I've been looking for a good example where composition clearly trumps inheritance, and might have something that is contrived, of course, but reasonable enough to demonstrate the principle and demonstrate some of the pain.
Coming up next – the Composition Kata.
If you like choices, you've come at the right time. You might think the decision making process starts by choosing between ASP.NET Web Forms and ASP.NET MVC, but if you widen your perspective a bit you'll find there are even more options outside the confines of the File –> New Project dialog in Visual Studio. And, these choices have steadily increased and matured over the last few years.
Here are just a few of the other options for writing a web app today:
- Nancy (lightweight and low ceremony)
- FubuMVC (convention-based and highly compositional)
- OpenRasta (a resource oriented framework for web sites and APIs)
- Service Stack (a web services framework)
- Oak (highly dynamic, frictionless)
Even when you restrict yourself to frameworks from Microsoft, there are still a bewildering number of decisions to make. Web Pages, Web Forms, Web API, or MVC?
Ultimately your job is to ship working software, and be happy about shipping the software. It's hard to build an application when you loathe working with the underlying technology. If you are brand new to all of this, I believe one of the first steps is to sit down by yourself and with your team, and figure out what you like and dislike about the available frameworks. If you are brand new to all of them, it would be worthwhile to spend a couple hours with each. Read about their design goals. Read the code examples as they will demonstrate the code you'll be living with.
Some of the questions to ask at this period include:
- What are my business requirements? Do I need to optimize for both mobile and desktop? Do I need to be highly scalable? What sort of authentication mechanisms do I need for my customers? Am I building a site, a service, or a combination of both?
- Do the abstractions make sense to me? Do the abstractions relate well with my mental modal of how things work on the web?
- What do I value the most? Testability? Flexibility? Simplicity? Past experience with an existing framework?
- What are my technology requirements? Am I tied to IIS and Windows or do I want the ability to run on Mono? Do I need to build an application that makes heavy use of JavaScript in the browser?
You have to answer these types of questions and narrow down the field based on how you perceive the capabilities of each framework. You can build almost anything with any of the above.
Eventually I'd recommend narrowing selections down to 2 or maybe 3 frameworks, then writing some code with each to get a good feeling for a what life with the framework is like.
When people ask me what to use, I tell them the choice of framework (and language) is a very personal choice. You have to evaluate questions like the questions listed above to figure out for yourself what framework will be the best for you, your team, and your business.
There are only a few hard and fast rules I can proclaim on this day in the month of February in the year 2013.
When starting a new application today:
- Do not use Silverlight
- Do not use LINQ to SQL
- Do not use WCF, unless you have no other option (e.g, to build a SOAP API).
- Do not use the Web Forms view engine for anything but a Web Forms application
- Don't forget: in larger applications the web layer is just a façade. Other architectural decisions should probably have a higher priority.