Building a FileReader Service For AngularJS: Promises, Promises

Tuesday, July 2, 2013 by K. Scott Allen
0 comments

Let’s build an AngularJS service to wrap an HTML 5 FileReader object.

The first question a curious person might ask is: why create a service? Why not use a FileReader directly from the code in a model or controller?

Here are two reasons:

1) To build an adapter around FileReader that works with promises instead of call back functions (which is what this post will focus on).

2) To achieve greater flexibility. Services in AngularJS can be decorated or replaced at runtime.

To understand the advantages of #1, we’ll need to learn about promises in AngularJS. For more general information about promises, see “What’s so great about JavaScript Promises”.

Promises and $q

In Angular, $q is the well known name of a promise provider, meaning you can use $q to create new promises. Here’s some code for a simple service that will perform async operations. The service requires $q as a dependency.

(function(module) {

    var slowService = function ($q) {

        var doWork = function () {
            var deferred = $q.defer();

            // asynch work will go here

            return deferred.promise;
        };

        return {
            doWork: doWork
        };
    };
    
    module.factory("slowService",
                   ["$q", slowService]);

}(angular.module("testApp")));

The doWork function uses $q.defer to create a a deferred object that represents the outstanding work for the service to complete. The function returns the deferred object’s promise property, which will give the caller an API for figuring out when the work is complete. This is the basic pattern most async services will use, but in order for anything interesting to happen with the promise, the service will also need to resolve or reject the promise when the async work is complete. Here is a new version of the doWork function .

var doWork = function (value, scope) {
    var deferred = $q.defer();

    setTimeout(function() {
        scope.$apply(function() {
            if (value === "bad") {
                deferred.reject("Bad call");
            } else {
                deferred.resolve(value);
            }
        });
    }, 2000);

    return deferred.promise;
};

This version is using setTimeout to simulate work that takes 2000 milliseconds to complete. Normally you’d want to use the Angular $timeout service instead of setTimeout, but setTimeout is here to illustrate an important point.

AngularJS promises do not propagate the result of a completed promise until the next digest cycle.

This means there has to be a call to scope.$apply (which will kick off a digest cycle) for the promise holder to have their callback functions invoked. With the $timeout service we wouldn’t need to use $scope.apply ourselves since the $timeout service will call into our code using $apply, but most things you’ll wrap with a service are not Angularized, so you’ll need to use $apply when resolving a promise.

Promises From The Client Perspective

Promises can lead to readable code for the client, as the code in the bottom of the controller demonstrates.

var TestController = function($scope, $log, slowService) {

    var callComplete = function (result) {
        $scope.serviceResult = result;
    };

    var callFailed = function(reason) {
        $scope.serviceResult = "Failed: " + reason;
    };

    var logCall = function() {
        $log.log("Service call completed");
    };

    $scope.serviceResult = "";

    slowService
        .doWork("Hello!", $scope)
        .then(callComplete, callFailed)
        .always(logCall);
};

One interesting feature of AngularJS is how the data-binding infrastructure understands how to work with promises. If all you want to do is assign the resolved value to a variable for data-binding, then you can assign the variable a promise instead of using a callback and Angular will know how to pick up the resolved value and update the view.

$scope.serviceResult =
    slowService.doWork("Hello!", $scope)
               .always(logCall);

And of course chained promises can kick off new async operations and the runtime will work through the promises in a serial fashion.

var TestController = function($scope, $log, slowService) {

    var saveResult = function (result) {
        $scope.callResults.push(result);
    };
 
    $scope.callResults = [];

    slowService
        .doWork("Hello", $scope)
        .then(saveResult)
        .then(function() {
            return slowService.doWork("World", $scope);
        })
        .then(saveResult);
};

With the above code and this bit of markup:

<li ng-repeat="result in callResults">
    {{ result }}
</li>

... then “World” appears on the screen roughly 2 seconds after “Hello”.

It’s interesting to note in the last example that if the first call fails, the 2nd call never happens (because the 2nd call is started from an “on success” function). If you want to know that the call failed you don’t have to add an error callback to every .then invocation.  A rejected promise will tunnel it’s way through the rest of the chain invoking error call backs as it goes, meaning you could get away with an error callback in the final .then.

For example, the following chained operations are doomed to failure since the service will reject the initial call with a parameter of “bad”.

slowService
    .doWork("bad", $scope)
    .then(saveResult)
    .then(function() {
        return slowService.doWork("World", $scope);
    })
    .then(saveResult, logFailure);

Even though the error handler logFailure doesn’t appear till the end of the chain, the initial failed service call will find it and the 2nd service is skipped.

In addition to serial processing, you can kick off multiple promises and wait for them to complete using $q.all.

var promises = [];
var parameters = ["Hello", "World", "Final Call"];

angular.forEach(parameters, function(parameter) {
    var promise = slowService.doWork(parameter, $scope).then(saveResult);
    promises.push(promise);
});

$q.all(promises).then(function() {
    $scope.message = "All calls complete!";
});

Now that we know a little more about promises, we can move on to the business of building a service in the next post.

On The Coexistence of ASP.NET MVC and WebAPI

Monday, July 1, 2013 by K. Scott Allen
10 comments

I’ve gotten more than a few questions over the last year on how to use the ASP.NET MVC framework and the Web API framework together. Do they work together? Should they work together? When should you use one or the other?

Here’s some general rules of thumb I use.

1. If the bulk of the application is generating HTML on the server, then there is no need to use the Web API. Even if I have the occasional call from JavaScript to get JSON data for templates or an autocomplete widget, using regular MVC controllers will suffice.

All ASP.NET MVC

One thing to keep in mind is that the Web API is a separate framework with its own dependency resolver, action filters, routing rules, model binding, and model serialization settings. Bringing in a 2nd set of all these components just to satisfy a few JSON requests from script is an increase in complexity.

2. If an application is loaded with JavaScripts and JSON flows back and forth to the server frequently, or if I have to support more clients than just the script in the pages from my site (some of whom might want XML or other formats), then it is a good time to create HTTP service endpoints and a more formal service API. These scenarios are just what Web API is made for and both MVC controllers and Web API controllers will happily coexist in the same project.

MVC With Web API

Although the Web API does add some complexity, it is also easier to build a proper service with the Web API. I can use the verb based routing and content negotiation features to build services oriented around resources, and the OData support and automatic help page generation of the Web API framework can come in handy.

3. I’m not a big fan of services for services sake. In the previous two figures, the MVC UI and Web API pieces are drawn to suggest how they are only facades on top of a core application. Most of the interesting things are defined in the application and not in the UI and Web API layers. When someone suggests that the MVC controllers should talk over HTTP to Web API controllers in the same application, all I can think about is putting a façade over a façade, which seems silly.

 

Tears for tiers

There are some valid reasons to go with such an architecture (see #4), but be cautious when creating new tiers.

4. It is more than reasonable to integrate multiple applications or large pieces of functionality using services and the Web API. This is a scenario where having web service calls inside or behind the MVC controllers of an application is almost required.

Big Enterprise

The above type of scenario usually involves large applications and multiple teams. Using a service layer allows for more flexibility and scale compared to sharing binaries, or integrating at the database level (shudder with fear).

Parting Words

There is no quick and easy answer to the questions in this space. If you are looking for guidance, hopefully I’ve provided some rules of thumb you can use to start thinking about the answer for your specific scenario. While thinking, remember these lines from the Zen of Python:

Simple is better than complex

Complex is better than complicated

AngularJS Videos From NDC 2013

Friday, June 28, 2013 by K. Scott Allen
0 comments

ndcosloI can’t say enough good things about The Norwegian Developers Conference.

This year there were a couple talks on AngularJS.

First there was Tom Dale, Peter Cooper, and Rob Conery in an EmberJS versus AngularJS cage match. We also interviewed Tom and Rob on Herding Code after the match was over and Tom gave us some great insights on the future direction of Ember.

Tom Dale, Peter Cooper and Rob Conery; Cage Match - EmberJS vs. Angular from NDCOslo on Vimeo.

 

I also did a long and rambling live coding session with AngularJS. Hopefully someone can make sense of it all.

Scott Allen: The Abstractions of AngularJS from NDCOslo on Vimeo.

IE11 Preview and the New Developer Tools

Thursday, June 27, 2013 by K. Scott Allen
9 comments

The Windows 8.1 preview includes a preview of Internet Explorer 11, which includes a new version of the F12 Developer Tools for inspecting, profiling, and debugging web sites.

The Good

The developer tools are now metrofied with flat buttons and an emphasis on content over window chrome. Although there are still a considerable number of icons and commands to press, it does seem easier to read and work with the information presented. All the important features are still here, though a few things seem to be missing (the ruler tool and link report as two examples), and they still behave the same and present the same information.

Dev Tools DOM Explorer

Update - yes, the DOM explorer tracks changes in real time now. Huge improvement!

The New

The emphasis is on performance with new “UI Responsiveness”, “Profiler”, and “Memory” sections.

The Memory tab is looking very useful for today’s apps and the heap snapshots are easier to use compared to the tools in other browsers. Likewise the code profiler is easy to work with and similar to the profiling tools for managed code in VS Ultimate.   

image

The “UI Responsiveness” tab is visually appealing and highly interactive but contains an enormous amount of information and will require some guidance and practice to use properly.

UI Responsive

The Missing

To get a full picture of what is happening on any given page, the IE dev tools will need to give us the ability to inspect local storage, session storage, IndexDB, and Application Cache. I didn’t find any of these in the current release.

Most worrisome is how there doesn’t appear to be any extensibility story for the tools. Framework oriented plugins for Knockout and Angular are popular in other browsers because they allow developers to work at a level above the code to see what is happening on a page. The ability to use simple HTML and JavaScript to create these types of plugins is what makes the other tools so popular. The IE dev tools will need a better extensibility story to keep web developers happy.

Convert A Directory Of PowerPoint Slides To PDF With Python

Wednesday, June 26, 2013 by K. Scott Allen
3 comments

There are many ways to automate Microsoft Office programs, but Python might be the prettiest:

import sys
import os
import glob
import win32com.client

def convert(files, formatType = 32):
    powerpoint = win32com.client.Dispatch("Powerpoint.Application")
    powerpoint.Visible = 1
    for filename in files:
        newname = os.path.splitext(filename)[0] + ".pdf"
        deck = powerpoint.Presentations.Open(filename)        
        deck.SaveAs(newname, formatType)
        deck.Close()
    powerpoint.Quit()

files = glob.glob(os.path.join(sys.argv[1],"*.ppt?"))
convert(files)

This script is using Python for Windows extensions.

Radio Buttons with AngularJS

Tuesday, June 25, 2013 by K. Scott Allen
1 comment

Last week we looked at using ngOptions in AngularJS to build a select list. Since the selections are mutually exclusive, we could have done something similar using radio buttons. There is no directive dedicated to radio buttons, but here’s a couple examples to show how easy they are to work with.

We’ll use the same controller as last time, but add a project attribute to the engineer.

var EngineeringController = function($scope) {

    $scope.engineer = {
        name: "Dani",
        currentActivity: "Testing code",
        project: "App A"
    };

    $scope.activities =        
        [
            "Writing code", "Testing code",
            "Fixing bugs", "Dancing"
        ];              
};

If we want to assign a project using hard coded inputs in the view, those inputs are easy to create and bind using ng-model.

<div data-ng-controller="EngineeringController">
    {{engineer.name }} is currently 
    {{ engineer.currentActivity }} for
    {{ engineer.project }}
    <label>
        <input type="radio" name="project" 
               value="App A" ng-model="engineer.project" />
        App A
    </label>
    <label>
        <input type="radio" name="project" 
               value="App B" ng-model="engineer.project" />
        App B
    </label>
    ...
</div>

A more interesting challenge is dynamically building a series of radio buttons using the activities array in the model. Here’s one approach using ng-repeat:

Choose a new activity:
<label data-ng-repeat="act in activities">
    <input
        name="currentActivity"
        type="radio"
        value="{{act}}"
        ng-model="engineer.currentActivity" />
        {{act}}
</label>

radio buttons in angularjsThe above works because all the inputs have the same name, bind to the same model property, and have distinct activity values. But, there’s one other feature of the model that makes the sample work, and that’s how we are binding to a nested property on the model (engineer.currentActivity).

Remember that an ng-repeat directive creates a child scope for each item, and the child scope inherits from the controller’s $scope object. Thus, the two way binding established with ng-model might not be setting a value in the $scope object of the controller, but in a child scope created by the repeater. In the code above, the binding works because the binding first needs to read the engineer property which is prototypically inherited from the $scope of the model, and then writes to the currentActivity property of that engineer object.

If the controller was flat like the following:

var EngineeringController = function ($scope) {

    $scope.currentActivity = "Testing code";

    $scope.activities =
        [
            "Writing code", "Testing code",
            "Fixing bugs", "Dancing"
        ];
};

Then the following markup would never write into $scope.currentActivity, but instead into a child scope, so this approach is probably not what you want.

<label data-ng-repeat="act in activities">
    <input
        name="currentActivity"
        type="radio"
        value="{{act}}"
        ng-model="currentActivity" />
        {{act}}
</label>

One way to fix the problem is to go back to using a more complex model (engineer.currentActivity would work), or to explicitly bind to the parent scope of the repeat item using $parent.

<input
    name="currentActivity"
    type="radio"
    value="{{act}}"
    ng-model="$parent.currentActivity" />

Theming Chrome Developer Tools

Monday, June 24, 2013 by K. Scott Allen
2 comments

The default styles for the Developer Tools in Chrome are a bit uninspiring.

Chrome Dev Tools DefaultFortunately, devthemes.com maintains a comprehensive list of themes for the Dev Tools as well as Sublime Text 2 and others.

My current favorite for Chrome is ZeroDarkMatrix.

Installation is as easy as downloading the theme’s custom.css file and replacing the existing file used by Chrome in ‘C:\%LOCALAPPDATA%\Google\Chrome\User Data\Default\User StyleSheets’ on Windows machines.

image

If you want to tweak styles yourself it can be helpful to look at the markup for the dev tools. You can inspect the markup by opening the dev tools on any web site (F12), then opening dev tools on the dev tools window (Shift+Ctrl+I). In the screen shot above, you can see the dev tools UI is built with HTML inside a <body> with an id of “-webkit-web-inspector”, which most themes will use as a prefix in the selectors for all the classes in a theme.

by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!