Data with AngularJS
In this article we’ll show you how to build JavaScript apps that can query, save, and maintain entity model data on the client using free and open source libraries including Angular and Breeze.
Introduction
Building a data-rich enterprise application that runs equally well on desktops, tablets, and other mobile devices is easier said than done. For quite a while it was nearly impossible for single-page applications (SPA) built in HTML, CSS, and JavaScript to rival their native-app brethren. But the times, they are a changing … and fast.
In this article we’ll show you how we’re building JavaScript apps that can query, save, and maintain entity model data on the client using free and open source libraries including Angular and Breeze.
The Challenge
In desktop/rich-client applications using .NET (WinForms, WCF, or Silverlight) or Java (Swing, SWT, or AWT), you can bind the on-screen controls directly to a rich data model, allowing UI updates to propagate to the entities and vice-versa. .NET and Java both have rich ORM-based entity managers such as Entity Framework and Hibernate that allow querying for entities, tracking changes, and performing unit-of-work saves.
How can we use a similar programming model for JavaScript applications?
The Solution
Angular and Breeze make it possible.
Angular focuses on presentation. It handles the binding between the UI and the data model. Changes in HTML elements propagate to the JavaScript entities and vice versa.
Breeze concentrates on data management. Breeze queries, saves, and takes care of all data interactions between client and server. Breeze automatically creates JavaScript model objects (called "entities") that match the shape of the data coming from the remote service. It adds business rules and the infrastructure to support validation, change tracking, and navigation to related entities. Breeze navigation properties automate traversal of the object graphs that are implicit in a relational model so you can walk the graph from a customer to its orders and from an order to its line items. Breeze tracks users’ changes and validates them with rules, some of which may have been propagated to the client from the server.
If you store data in a database, query and save data as complex object graphs, and share graphs across multiple views—and want to do it in JavaScript—there is no better way than with Breeze.
The Todo-Angular sample
We’ll use a Todo application to demonstrate how Angular and Breeze make building single-page apps much easier than they would be if you tried to write all of the data binding and management by hand.
Download the samples package from BreezeJS.com. The Todo-Angular sample, including all source code and prerequisite libraries, can be found in the /Samples/Todo-Angular/ directory. Open it in Visual Studio, build it, and run it – with (F5) or without (Ctrl-F5) debugging.
Todo-Angular is a simple CRUD (create, read, update, delete) app. On a single screen you can create items, update their descriptions, change their state, or delete them. All of the application logic executes in JavaScript on the client. The server merely responds to data requests by querying and saving Todos to a server-side SQL database.
The essential workflow is as follows:
-
Breeze sends a query to the server to retrieve the Todo items. The
server sends a JSON response, which Breeze turns into Todo entities (rich
JavaScript objects) on the client.
- Angular binds the Todo entities to the HTML elements (e.g. textboxes,
checkboxes) and listens for changes.
- When a value is changed on the HTML form (e.g. a user edits the description of a Todo), Angular sees the change and propagates the new value to the underlying Todo entity.
- Breeze notices the change to the Todo entity and marks it as modified.
- When a save is triggered, Breeze sends the changed Todo entities to the server.
Under the hood, the app architecture is Model-View-Control (MVC) which both Angular and Breeze adhere to nicely.
There’s only one web page, Index.html, whose primary responsibility is to host the client application. As such, it has CSS at the top, scripts at the bottom, and a layout section in the middle.
The View
For simplicity, the Todo view—the HTML that displays Todos and accepts
user input—is baked into the HTML as well, within the collapsed
"applicationHost
" <div>
.
A more sophisticated app with multiple client pages would define the
Todo view (and other views) in separate files which client-side app logic would
swap into and out of the "applicationhost
". That’s looking down the road. In
this sample we’re just trying to get a grip on the basics.
Here are a few excerpts of the view HTML positioned over the visuals
they define.
Angular data binding
The "data-ng- ..." attributes are Angular "directives". Directives bind aspects of the HTML widgets to properties and methods in a controller.
Many of the directive bind to members of the controller itself. Here’s an excerpt from the controller defined in controller.js:
For those new to Angular, the $scope
is the
data bound object. You could think of it as the ViewModel if that term seems
more familiar.
When Angular creates a new instance of the controller, it passes an empty $scope object to the controller’s definition function; that’s the anonymous function in the image above.
The controller adds properties and methods to this $scope, named to match the declaration in the HTML.
In the following snapshot, we see the "addItem()
" in the
HTML matches the $scope.addItem
method, and the "newTodo
" associated with the
input textbox matches $scope.newTodo
.
The $scope.items
array holds the Todo items that were retrieved by
query. This is bound to a "repeater", the <li>
element, which describes a
template for displaying the individual Todo items.
Some of the Angular directives within that template bind to properties
of an individual Todo item entity rather than the controller. For example, the
checkbox is bound to the item’s IsDone
property while the label is bound
to the item’s Description
property.
Custom directives
One of Angular’s strengths is the ability to extend its native binding directives with custom directives to meet application-specific needs. This module defines some custom Angular directives that listen to focus changes.
Here we see the custom "onBlur
" directive, defined within
the controller.js file, applied to the item description textbox
("data-on-blur").
When the user leaves the textbox after editing the
description, the textbox loses focus. The directive detects the "blur" and
calls the "completeEdit
" method on the controller.
From a broader perspective, we see that the controller manages the
application workflow by mediating between the view and the model layers. It
relies on Angular to get to the screen and delegates to the dataservice
when it needs to acquire and manipulate Todos items.
The dataservice
handles all entity creation, queries, and saves.
The methods often return promises
from the asynchronous operations so that the controller can respond
appropriately later when these operations complete.
Breeze itself turns controller commands into HTTP requests to a single
ASP.NET Web API controller on the server. That controller delegates to a Breeze.NET
component, EFContextProvider
which handles interactions with the Entity
Framework and the application’s "Code First" TodoItem model. The raw data are
stored in a SQL Server CE database.
A slight Breeze
The Breeze documentation, live tutorial, and samples are the best ways to learn what Breeze development is about. Let’s look at just one of the dataservice.js methods to whet your appetite.
The controller passes in a flag to tell the dataservice
whether it should return all Todos—including the archived Todos—or just the
active Todos. The flag comes from the controller’s isArchived
property
which is bound to the "Show archived" checkbox.
We begin by creating a Breeze query object that targets a remote service method called "Todos". If we simply executed that query now, the remote service method would return every Todo item in the database.
But the developer wrote that service method so it will
respond to an OData-style query. So, on the client, we add an orderBy
clause telling the service to sort the query results, by creation date. The
sorting will occur on the data tier, before the data come over the wire.
If the user only wants to see active Todos (i.e., the
includeArchived
flag is false), we need to exclude the archived Todos by adding
a filter. The "where" clause adds that filter to the query. Now when we execute
the query, the results will consist of just the active Todos, sorted by
creation date.
This query building strategy and syntax should remind you of LINQ.
In the final statement, a Breeze EntityManager
executes the query. The query operation is asynchronous and returns a promise
to the controller: a promise to notify the controller when the query succeeds,
or fails. Here’s how the controller called the dataservice and handled the
promise.
After a pause, the remote service returns Todo item data to
the client as JSON. Breeze converts that JSON into Breeze entities which are
equipped with validation, change tracking, and other capabilities of the Breeze
system. These entities are merged into the EntityManager
’s cache before
they are returned to the controller as query results.
When the user makes changes on screen, the corresponding
Todo entity in cache changes to a "Modified" state. The application is designed
to save immediately so the controller tells the dataservice which ultimately
delegates to a call upon the EntityManager
’s saveChanges
method:
It’s that simple. The manager collects all cached entities with unsaved changes and sends them to the remote service as a change-set. The remote service, unpacks the change-set, applies the appropriate business logic, and stores it to the database as a single transaction. The business logic (very little in this sample) is yours; the rest of the plumbing is handled by Breeze.
We should mention that the dataservice.js in this sample is almost identical to the dataservice for a parallel Todo sample that uses Knockout rather than Angular. It takes a single line of configuration to switch between Angular, Knockout, Backbone or some other model library of your choice.
Breeze itself has no intrinsic affinity for any particular JavaScript data binding library.
That’s the Todo-Angular app in a nutshell.
The JavaScript inventory
The Todo-Angular client depends on five free and open-source third-party libraries and three application scripts.
Third-party libraries
All third party libraries are in the Scripts folder.
Angular.js
Angular handles the plumbing – the data-binding, event monitoring, and DOM manipulation for the presentation layer.
Breeze.js
Breeze takes care of the "Model" concerns in the MVC triad. It maintains a client side cache of persistent model objects consisting of newly created entities and entities materialized by a query. Breeze handles your query and save operations.
jQuery.js
There’s not a lot of jQuery in this particular sample. Breeze is relying on jQuery.ajax for communication with the back-end service.
Q.js
Q assists in managing asynchronous operations through CommonJs promises.
toastr.js
Toastr displays process and error notifications in "toast" windows that float up from the lower right.
Client-side scripts
The client-side application scripts are in the Scripts/app folder.
controller.js
The controller.js defines two Angular modules,
TodoMain
and TodoCtrl
. Custom directives are defined in TodoMain
. TodoCtrl
is
the controller module that manages the view.
dataservice.js
The dataservice.js provides the modeling and client-side data access layer for the application. It leans heavily on Breeze.
logger.js
The logger.js is merely an abstraction wrapped around the 3rd party toastr library. You could rip toastr out and log to console if you prefer.
What about the server?
Both AngularJS and BreezeJS are pure JavaScript libraries. Neither requires .NET, Visual Studio, Entity Framework, or ASP.NET, and you can write the server however you’d like.
You do need a server of some kind to deliver the web assets and data services. We used .NET for this example because it’s quick and effective for folks already building on the Microsoft stack. It helps that Breeze ships with components to ease development of Web API and Entity Framework back-ends.
This Todo-Angular server is an ASP.NET Web Application. It hosts all the client-side assets as well as an ASP.NET MVC4 Web API service that queries and saves to a SQL Server database with the help of an Entity Framework Code First model. This article concentrates on client-side development so will just leave it at that for now.
Learn more
In addition to the core docs and API, you can find detailed information specific to the Todo-Angular sample, including:
About
Breeze is actively developed by IdeaBlade. Follow @BreezeJS on Twitter and Like us on Facebook.