Let’s review some relevant terminology:
Library - a collection of functions used to write web apps. Your code is in charge, and it references the library when it needs to.
Framework - a particular implementation of a web application, where code fills in the details. The framework is in charge, and it references your code when it needs something app specific.
Let’s compare features that are similar and review how they differ.
Data Binding is the process of establishing a connection between the application UI and the business logic. If the settings and notifications are configured correctly, the data reflects changes made in the UI. This also means that when the data is changed, the UI will represent that change.
Let’s take a look at data binding process for both libraries. We will assume that our underlying data model is:
In order to perform two way binding using KnockoutJS we need to replace the model properties with a ko.observable wrapper:
Let’s see how to declare and apply bindings in HTML using the two technologies:
Let’s analyze the differences. In the HTML syntax for Knockout everything is done using the data-bind attribute and appropriate binding type; however, the need to specify all properties as observable requires additional effort. Mappings need to be performed when loading JSON data from the server to convert properties to observables. There is a mapping plugin that can be used to make this easier, but it is your responsibility to manage the mapping when retrieving data and when sending data back to the server.
Angular syntax for outputting values is much simpler and compact. It makes it easier to read and compose. The major difference is the binding methodology. Where Knockout binds to the provided model, Angular binds to the special $scope object.
Additionally, Knockout can only apply bindings once. If you try to apply bindings again it will throw an error. In Angular, however, scopes can be nested. This approach makes Angular views and controllers independent and reusable, and as a result, they can be tested independently. An example of this nested approach is shown below:
Both libraries support templating. This helps break code into small, maintainable pieces.
Angular is superior in that it allows templates to be stored in external HTML files and loaded dynamically. This results in better organization and maintenance of template code. All we need to do is provide the template URL:
With both technologies you are not limited to built-in functionality. Angular allows you to extend the HTML vocabulary of your application. The resulting environment is extraordinarily expressive, readable, and quick to develop. Angular uses a concept of Directives which allows you to attach a specific behavior to the DOM elements or transform it:
Equivalent functionality can be implemented in Knockout by writing custom bindings.
Both libraries come with built-in directives and bindings, and although these examples are very basic, they show how each library can be extended to be more sophisticated.
Knockout uses the Observable pattern to track changes and notify registered subscribers.
Because Angular works with plain objects, it observes variables using a dirty checking technique. Every time an expression is evaluated it compares current object values with previous object values.
It would be fair to say that Knockout can only be compared to a subset of Angular features. Angular is a more extensive framework, and includes the following additional features:
Modules - a module is a container for a set of components. Those components can be controllers, services, filters, directives and etc. From .NET or Java perspective, a module is more like a namespace. It enables you to package code into reusable components. Modules can reference other modules. They serve as application building blocks.
Services - a service can be used to organize and share code across your app. Each service is a singleton, and all components reference a single service instance. Angular contains a number of built in services including:
$http - used to make AJAX requests to the remote servers
$q - promise/deferred implementation inspired by Kris Kowal's Q
$log - service for logging. By default writes to browser console if present
Dependency Injection - the Angular injector subsystem is in charge of creating components, resolving their dependencies, and providing them to other components as requested.
Scopes - arranged in hierarchical structure which mimic the DOM structure of the application, Scopes can watch expressions and propagate events:
For example login service can broadcast a login event when user logs in
Then components that need to act based on this event are simply subscribed to the event:
Filters - A filter formats the value of an expression for display to the user. They can be used in view templates, controllers or services. It is easy to define your own filter. Filters can be applied to expressions in view templates using the following syntax:
Form Validation - form and controls provide validation services, so that the user can be notified of invalid input.
Internationalization and Localization
When working with Knockout, this functionality is not available in the core library, but can be added by using external libraries or custom logic.
Routing is a great feature that allows management of application states. and back/forward browser history navigation. Knockout does not support routing.
AngularUI Router is a routing framework for AngularJS, which allows you to organize the parts of your interface into a state machine. Unlike the $route service in the Angular ngRoute module, which is organized around URL routes, UI-Router is organized around states.
States are bound to named, nested and parallel views allowing you to manage your application's interfaces with ease. Additionally, states can be nested within each other.
Below is a sample Angular routing setup:
Angular is written with testability in mind, but it still requires some additional effort to integrate a test framework.
Protractor is a a popular end-to-end test framework for AngularJS applications. Protractor is a Node.js program built on top of WebDriverJS. Protractor runs tests against your application running in a real browser, interacting with it as a user would.
Knockout apps can be tested using similar methodologies, however, Knockout does not inherently result in testable code.
Mozilla Firefox (versions 3.5 - current)
Google Chrome (current)
Microsoft Internet Explorer (versions 6 - 11)
Apple Safari for Mac OS (current)
Apple Safari for iOS (versions 6 - 8)
Opera (current version)
Safari, Chrome, Firefox, Opera, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari)
Versions 1.2 and later of AngularJS do not support Internet Explorer versions 6 or 7
Versions 1.3 and later of AngularJS drop support for Internet Explorer 8
Knockout documentation for data binding syntax is extensive. Utility methods provided by the library are almost not existent.
Angular documentation is very well organized and has tons of information including interactive examples. The learning curve is steeper for Angular, as the library is much more conceptual and wider in application.
Angular seems to be more widely adopted with a broader user base. The table below shows some interesting ecosystem statistics:
Knockout has a low barrier of entry, but is also harder to manage when code base and complexity grows. It is not easy to build the necessary infrastructure correctly, and poor decisions made in structuring code may cost a lot to fix in the future.
Angular’s ability to bind directly to plain objects, modular structure, and strict development guidelines prevent many issues right from the start, and provide a strong architectural foundation for the application.