Click here to Skip to main content
Click here to Skip to main content

Data with AngularJS

By , 18 Jan 2013

Editorial Note

This article is in the Product Showcase section for our sponsors at CodeProject. These reviews are intended to provide you with information on products and services that we consider useful and of value to developers.

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:

  1. 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.
  2. Angular binds the Todo entities to the HTML elements (e.g. textboxes, checkboxes) and listens for changes.
  3. 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.
  4. Breeze notices the change to the Todo entity and marks it as modified.
  5. 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

johnlantz

United States United States
No Biography provided
Follow on   Twitter

Comments and Discussions

 
QuestionChanging query on Client PinmemberTim Schwallie31-Jan-13 8:13 
How does security on this library work?
Or can anybody change the query to query any table in the database?
AnswerRe: Changing query on Client Pinmemberjohnlantz5-Feb-13 9:02 
SuggestionBreeze with Angular does not support IE8 Pinmemberwadep21-Jan-13 1:24 
GeneralRe: Breeze with Angular does not support IE8 Pinmemberjohnlantz25-Jan-13 7:50 
QuestionVirtualisation PinmemberMember 976946019-Jan-13 3:57 
AnswerRe: Virtualisation Pinmemberjohnlantz25-Jan-13 9:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140421.2 | Last Updated 18 Jan 2013
Article Copyright 2013 by johnlantz
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid