Check out our new training course on AngularJS for Flex Developers

Creating an AngularJS Transform Function to post to ColdFusion

Recently a colleague of mine had some issues posting from AngularJS to a ColdFusion CFC. I thought back to my training course on AngularJS and thought "Hey, didn't I write an article about that." I did; and I also put together a screencast as part of the video series in my "Life After Flex" master course.

I watched it again and impressed myself. So here it is for all to see:

Be sure to pick up the full training course.

Oh, if you were on our mailing list you would have gotten a nice big discount on the master course this month:

Sign up for DotComIt's Monthly Technical Newsletter

An Introduction to Web Components

I wrote this up for the DotComIt newsletter in February, and wanted to post it here too. This is my introduction to Web Components.

What are Web Components?

Web Components are reusable browser widgets. They are being created as a set of standards by the W3C. In a practical sense, Web Components are like Angular directives, but independent of any singular JavaScript framework and built right into the browser. You use Web Components to bundle markup and styles into your own encapsulated, reusable entity.

There are four separate elements of web components:

  • Custom Elements: A custom element is, basically, your own HTML tag.
  • HTML Imports: An HTML Import is like an import in other programming languages, such as ActionScript or Java. They basically point to a piece of encapsulated code and make it available for use in the page.
  • Templates: Templates allow you to define fragments of an HTML page for reuse.
  • Shadow DOM: The Shadow DOM is used to define functional boundaries between the Web Component and the page that uses it. This, essentially, defines your API. It prevents conflicts between CSS and named HTML elements inside the Web Component and outside of it.

This article will server as an introduction to all these aspects.

One warning before we get into it; Web Components are a new technology and not supported by all browsers. These samples were built and tested in Chrome, but do not seem to work elsewhere.

Get Polymer

Polymer is a common framework used for building web components, and we're going to make use of Polymer in this article. You can find information about getting Polymer. You'll just need to put the polymer files in a web accessible directory. I put mine in "/bower_components/polymer/polymer.html".

Sample 0: No Web Component

I want to start this with a simple example. This sample will be a web page, that has some centered text on it:


<html>
<head lang="en">
<meta charset="UTF-8">
<title>Web Components: Sample 0</title>
<style>
.centeredContent{
text-align: center;
}
</style>
</head>
<body>
<div class="centeredContent" >
Hello World!
</div>
</body>
</html>

The "Hello World" text is put inside a div. The text is centered with the centeredContent style. This is about as simple as it comes. Your browser should look something like this:

Check out a running sample.

For the remainder of this article we are going to iterate over a web component that will center its text. This is a simple sample for example purposes, but can be much more complex.

Sample 1: Centered Text Web Component

Let's create our first Web Component. Let's start with a simple web page:


<html>
<head lang="en">
<meta charset="UTF-8">
<title>Web Components: Sample 1: A Simple Component</title>
</head>
<body>
</body>
</html>

Since we will be using the Polymer framework, the first step is to import it. Put the import statement in the head of the HTML Page:


<link rel="import" href="bower_components/polymer/polymer.html">

The import statement is based off the link tag, which I primarily use to import external style sheets. The syntax should be familiar to you. The rel says import and the href is the link to the HTML file that you're importing; in this case the polymer framework.

Next, define the web component with the polymer-element tag:


<polymer-element name="my-HelloWorld" noscript>
</polymer-element>

This tag can be added to the body of the page. The name of our component is specified as my-HellowWorld; but currently it does nothing. A template is needed for the component, so inside the polymer-element add the template tag:


<template>
</template>

So far so good! Next, add the content inside the template; which will be the style for centering content and the div that includes the content:


<style>
.centeredContent{
text-align: center;
}
</style>
<div class="centeredContent" >
Hello World inside component!
</div>

Finally, you can use the Web Component as if it were a standard HTML tag:


<my-HelloWorld ></my-HelloWorld>
<my-HelloWorld ></my-HelloWorld>

See this in action:

This example touched on three of primary elements of creating Web Components. We used an import to import the polymer framework. We used a template to create our own template. And we created a custom element that is used to create an instance of the web component.

Sample 2: Defining Content with Attributes

The Web Component we've created doesn't have much utility yet. It only displays items and does not give us any external control over the component. We can change that, by adding support for attributes to the component. We are going to add a single attribute, named text and that attribute will be used to determine the content that the component will center.

First, add the attributes attribute to the polymer-element:


<polymer-element name="my-HelloWorld" attributes="text" noscript>

When we want to display the text inside the div, we can do this:


<div class="centeredContent" >
{{text}}
</div>

The double curly bracket syntax that is prevalent in Angular, so you should be familiar with it from my past writings. Flex uses a similar syntax--except with just a single curly bracket. The syntax does binding under the hood. It means that whenever the text value changes, the internal component display will also update. Here is the code that uses the attribute:


<my-HelloWorld text="Hello World attribute!" ></my-HelloWorld>
<my-HelloWorld text="Hello World attribute 2!" ></my-HelloWorld>

The attribute we defined is used just like any other attribute on an HTML tag.

Try this in action, and you should see a screen similar to this:

Sample 3: Defining Content Body Text

In addition to adding attributes, you can also access the tag's body text from within the component. Start from sample 1 to create this modification. Inside the template you can reference the body text, or inner HTML, of the tag using the content tag:


<div class="centeredContent" >
<content></content>
</div>

Then you specify the content to send into the tag like this:


<my-HelloWorld >Hello World Body Text!</my-HelloWorld>
<my-HelloWorld >Hello World Body Text 2!</my-HelloWorld>

The results can be shown here:

Sample 4: Separate Files

In real development you won't want to define your Web Components in the same file. Doing so limits reuse, which defeats the purpose of componentizing your code in the first place. Let's create a new file, component4.html and move our component into it:


<link rel="import" href="bower_components/polymer/polymer.html">

<polymer-element name="my-HelloWorld" attributes="text" noscript>
<template>
<style>
.centeredContent{
text-align: center;
}
</style>
<div class="centeredContent" >
{{text}}
</div>
</template>
</polymer-element>

This code contains the import of the polymer framework. The code includes the polymer definition of the my-HelloWorld component and also contains the text attribute and the template with our style and the centered content. The main page becomes much simpler now:


<html>
<head lang="en">
<meta charset="UTF-8">
<title>Web Components: Sample 3: A Component in a Different File</title>
<link rel="import" href="Component4.html">
</head>
<body>
<my-HelloWorld text="Hello World Separate File" ></my-HelloWorld>
<my-HelloWorld text="Hello World Separate File 2" ></my-HelloWorld>

</body>
</html>

This new main page imports Component4.html, but does not import the Polymer framework, because that is imported directly into the component, and not used in the main page.

This is the sample here:

Sample 5: Shadow DOM Isolation

One thing I didn't want to go into details on, but did want to touch on was the shadow DOM. The shadow DOM means that the DOM inside the Web Component is isolated from the DOM of the main page. This will prevent styles from different components, or your main application, from interfering with the main component styles. Let's take a look at Component5.html:


<link rel="import" href="bower_components/polymer/polymer.html">

<polymer-element name="my-HelloWorld" attributes="text" noscript>
<template>
<style>
.alignedContent{
text-align: center;
}
</style>
<div class="alignedContent" >
{{text}}
</div>
</template>
</polymer-element>

This is pretty similar to the example we saw in sample 4. The main difference is that I named the style alignedContent instead of centeredContent. The text inside the component will center the content. But, let's use the same style inside the main index file to right align content:


<html>
<head lang="en">
<meta charset="UTF-8">
<title>Web Components: Sample 3: Shadow DOM Samples</title>
<link rel="import" href="Component5.html">
<style>
.alignedContent{
text-align: right;
}
</style>

</head>
<body>

<my-HelloWorld text="Hello World Shadow DOM Example" ></my-HelloWorld>

<div class="alignedContent" >
Shadow DOM Example
</div>
</body>
</html>

To reiterate, the alignedContent style will center content in the Web Component, but will right align content in the main file. Run this code and you'll see:

You can see the top text is centered while the bottom text is right aligned. Two styles with the same name do not interfere with each other. This is why we love encapsulation.

When using browser developer tools by default the Shadow DOM element is hidden; however you can enable them if you want. This is a great debugging tool because if you're just using a component, you may want to focus on your own code without drilling down into the code of the component that you use. A parallel in the Flex world is that you often want to debug your own code, but do not need to drill into the code behind the Flex Framework code or code from complimentary frameworks such as Robotlegs or Swiz.

Final thoughts

Here are some good resources for reading up on web components:

Web Components, as an evolving standard, are not supported in all browsers yet. The polymer framework helps by providing support for browsers that don't have web components implemented natively. That is why most examples about web components use the framework. I like the concept, and this is something to watch in the future.

Sign up for DotComIt's Monthly Technical Newsletter

Turning the ESRI Map Component into an Angular Directive

A client of mine builds a lot of mapping applications using the ESRI API. The ESRI HTML5 Map components are built on top of the DOJO toolkit, a JavaScript framework and UI library. DOJO has its' own way of doing things. My client likes the Angular approach better than DOJO, so they wanted to be able to use the DOJO Mapping component as an Angular directive. How do we do that?

There are lots of blog posts on using the ESRI Mapping components inside an Angular application. This was the best one I found, however I could not find any ready to go samples. This article intends to explain exactly my approach to make the DOJO component work as an Angular directive.

Why is there a problem?

DOJO is JavaScript code, right? Any JavaScript code can be wrapped up in an Angular directive, right? Why does the ESRI mapping component present problems? The problem is that DOJO uses a “load on demand” approach, and that brings out issues where the AngularJS Directive is created in the browser before the DOJO object is loaded. Getting Angular and DOJO to sync up was the root of my problem.

Create the Main Index

The main index will be an HTML page that will display the map using the Angular directive we will create. First create a basic outline:


<html>
<head lang="en">
<meta charset="UTF-8">
<link rel="stylesheet" href="http://js.arcgis.com/3.9/js/esri/css/esri.css" />
<script src="http://js.arcgis.com/3.9/"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.10/angular.min.js"></script>
<script src="js/ESRIDirective.js" ></script>
</head>
<body >
</body>
</html>

There are four important elements of the HTML header. The first is a link tag to load the ESRI style sheet. This is loaded directly from the ESRI servers. The second loads the ESRI libraries, also loaded from the ESRI servers. The third library loads the Angular library from the Google CDN. The final script tag will load our local ESRIDirective.js file. This directive will include the finished Angular library, which will be built later in this article.

Next, create an AngularJS module and controller for testing the application:


<script>
var mapTest = angular.module('mapTest',['map']);
mapTest.controller('mapTestController',['$scope', function($scope){
$scope.title = "Hello Map";
}]);
</script>

This creates a new AngularJS Module named mapTest. One custom directive is passed into it, named map. This is the directive that will be defined in the ESRIDirective.js script. A single controller is created, named mapTestController. It creates a single variable in the $scope, named title.

We flesh out the body of the HTML page to load the map:


<body ng-app="mapTest" >
<div ng-controller="mapTestController">
<h1>{{title}}</h1>
<esri-map zoom="4" basemap="streets" id="mapID">
</esri-map>
</div> -
</body>

I modified the body tag to add the ngApp directive on it. Then I added a div which points to the mapTestController with the ngController directive. The title from the directive's $scope is displayed. Then the map directive is used. Three attributes are specified directly on the esriMap directive: zoom, basemap, and id. These relate to specifics of the ESRI mapping API.

Trying to load this app in a browser will just give you errors, because the ESRIDirective.js file has not yet been created. We can tackle that next.

Write the JavaScript Code

Create the JavaScript file ESRIDirective.js in a js directory relative to the main index file. This is the file that will contain the Angular mapping directive based on the ESRI DOJO component. First create an Angular module:


var esriMap = angular.module('map', []);

When you want to create Angular directives that can be shared across different modules, it is a common approach to create the directive in a separate module. The module is passed into the main angular application as part of the dependency array.

Next, I want to create a mapObjectWrapper:


var mapObjectWrapper = function(){
this.map = undefined
}

This is a variable that will exist as part of the HTML page. It exists outside of AngularJS and independent of DOJO. This object will wrap the DOJO map object, however it is undefined in its default state.

Next, create an AngularJS factory to wrap the mapObjectWrapper:


esriMap.factory('esriMapService',function(){
return mapObjectWrapper;
})

This factory allows us to use the mapObjectWrapper inside of an Angular controller without breaking the dependency injection principle of AngularJS that allows for easy module testing.

Now create the directive:


esriMap.directive('esriMap', function () {
return {
restrict: 'EA',
controller: 'MapController',
link: function (scope, element, attrs, ctrl) {
ctrl.init(element);
}
};
});

The restrict property of the directive allows the directive to be used as an entity, or as an attribute. In the code we shared in the previous section it was used as an Entity, like this:


<esri-map>
</esri-map>

However, the could also have been used as an attribute, like this:


<div esri-map>
</div>

This directive specifies both a controller and a link function. The controller refers to MapController, something we haven't created yet. The link function does not contain any code other than to execute an init() method on the controller. This approach is used so that the controller is separate from the directive and can be tested independently.

The real meat of this directive is in the controller, so let's create that next:


esriMap.controller('MapController',
['$rootScope', '$scope', '$attrs','esriMapService',
function ($rootScope, $scope, $attrs, esriMapService) {
$scope.mapService = esriMapService;
$scope.mapService.scope = $scope;
}

The previous code block creates a controller on the esriMap module. The controller is named MapController. There are four services passed into it:

  • $rootScope: The $rootScope service will be used for broadcasting evnts to other aspects of the application.
  • $scope: The angular $scope service is used for sharing data between a view and controller.
  • $attrs: The $attrs service will contain all the attributes on our custom HTML element. It will allow us to introspect the attributes if need be.
  • esriMapService: The esriMapService is the custom service we created, which wraps the mapObjectWrapper.The mapService is saved to the local $scope, and the local $scope is saved as a property on the mapService object. This is so that our DOJO code can execute a function on the the directive’s $scope once it is loaded. You'll see this code later.

Here is the init() function:


this.init = function (element) {
if (!$attrs.id) { throw new Error('\'id\' is required for a map.'); }
$scope.$element = element;
if(!$scope.mapService.map){
return;
}
$scope.recreateMap();
};

The init() function is called from the link in the directive's controller. The first piece of code in the the method is to make sure that an id attribute exists on the directive's tag. The ID is required by the ESRI map component. The element argument represents the tag that created the directive. The element is stored into the controller’s $scope for later reference.

If the mapService.map variable is not yet defined, then the method’s execution stops. Otherwise, a recreateMap() method is called in the controller:


$scope.recreateMap = function(){
createDiv();
createMap();
}

This method just calls two other methods. The createDiv() method is used to create a separate div required by the mapping component. The createMap() component will create a map on that div. First, create a variable to contain the map div:


var mapDiv

Now, we can examine the method:


var createDiv = function () {
if(mapDiv){
return;
}
mapDiv = document.createElement('div');
mapDiv.setAttribute('id', $attrs.id);
$scope.$element.removeAttr('id');
$scope.$element.append(mapDiv);
};

If the mapDiv already exists, then the function processing is terminated. If the mapDiv doesn't exist, then a new div is created. It is given the same ID that is specified as an attribute. The id attribute is removed from the main tag. This is so that the map component does not get confused by two separate divs identically named. Finally the new map div is added to the DOM as a child of the main element.

Here is the createMap function:


var createMap = function () {
if(!$scope.mapService.map){
return;
}
if(!mapDiv){
return;
}
var options = {
center: $attrs.center ? JSON.parse($attrs.center) : [-56.049, 38.485],
zoom: $attrs.zoom ? parseInt($attrs.zoom) : 10,
basemap: $attrs.basemap ? $attrs.basemap : 'streets'
};
$scope.map = new $scope.mapService.map($attrs.id, options);
$scope.map.on('load', function () { $rootScope.$broadcast('map-load'); });
$scope.map.on('click', function (e) { $rootScope.$broadcast('map-click', e); });
};

First, the method checks to see if the mapService is loaded and if the mapDiv is created. If either of these conditions is false, then the code is not executed.

Next the code creates an options object. This options object properties are created by introspecting the attributes on the directive's main tag, and uses those attributes to create a options object to send to the map. In this case, only three are implemented: center, zoom, and basemap.

I'm unsure how I feel about the code examining the attributes to create the options object. I’d rather pass this responsibility back to the directive user, so they can add or remove properties as needed. The current approach will need to change the directive code if we want to add, or remove, option parameters. In my Angular travels it is more common to see an options object passed into the directive, and that options object contains all the relevant parameters. I’d much prefer that to introspecting the attributes however I did not have time to change that for this proof of principle demo.

The next line of the method uses the DOJO mapService’s map() method to create the map on the screen. The last two lines add load and click event handlers on the map. This uses the $rootScope to broadcast events, essentially telling anyone listening that these actions occurred on the map.

The final piece of code is the DOJO statement to load ESRI’s map function. This should exist outside of any Angular code:


require(['esri/map'], function (Map) {
mapObjectWrapper.map = Map;
mapObjectWrapper.scope.recreateMap();
});

The DOJO component is loaded using the require() method. That means it is not loaded immediately, but queued up to be loaded as it is needed. Once loaded, this method accesses the mapObjectWrapper directly. It saves the map as a parameter inside the object, and then executes the recreateMap() function on the controller's scope. Remember when we added the scope to the esriMapService? This is why. It provides a hook so that the DOJO code can communicate with the Angular directive.

Final Thoughts

You can view a working demo here. The client I built this prototype for also put the code in their GitHub account. My own fork is here.

Sign up for DotComIt's Monthly Technical Newsletter

How do I run code on Browser Resize with AngularJS?

I was working on a client application and wanted to execute code inside a controller whenever the browser resized.

My purpose was to change a ng-class value, based on the available width. I had it all working great on the initial application load, but the client wanted to make sure this display update would take place if the browser resized and without having to reload the app.

How can I run code when the browser resizes? I imagine there are a bunch of ways, but in the context of AngularJS this is how I did it.

First add the $window service to your controller:


function someCtrl($scope, $window) {
}

With the $window service and the Angular element, you can get a reference to the JQuery object:


var w = angular.element($window);

I believe this should work even if you don't have the full JQuery version loaded into your app, because AngularJS has a version of JQuery under the hood.

Then you can use bind() on resize.


w.bind('resize', function () {
console.log('resize');
});

The bind() function, in this case, will execute the function whenever the browser resizes.

Here is a Plunkr to demo this.

Sign up for DotComIt's Monthly Technical Newsletter

What technology should I add to Life After Flex?

If you don't know, I put together a training course on AngularJS for Flex Developers. It includes some free books, and a bunch of additional (non-free) content including six hours of screencasts.

I'd like to extend the series to include more technologies, and have put together this quiz to collect your feedback. It is only three questions and should take less than a minute, so go in and throw your two cents.

I'd welcome the feedback.

Watch my AngularJS For Flex Developer's Presentation from 360|Flex

The 360|Flex team has posted a video of my AngularJS for Flex Developers presentation.

The audio has a bit of an echo, but otherwise I thought it went pretty well.

Why didn't my Angular View update after changing the $Scope variable?

Binding in AngularJS works magically. When an element in the controller changes the view is updated automatically. When an input in the view is updated, the controller value is automatically updated.

This is because every time the user interacts with the app, AngularJS automatically runs the $digest() method which automatically updates all bindings.

I am working on an app for a client that needed to execute JavaScript code when a binding changes. I had one view, and controller, which displayed some data filtering options to the user. A second view, and controller, displayed data loaded from the remote services, based on the filtering options. When the filtering elements were changed, a remote service call was made in the filtering view, and the results needed to modify the data view.

However, I discovered that when the results came back from the service call, the view was not updating with the new data. Why is that?

There are a few things at play here and I'm going to start with some simple examples of binding, then expand to discuss $watch(), and finally I'll talk about how to use $apply() to solve the problem.

Setting up a Simple Application with Binding

To demonstrate watches I'm going to start with a simple application. It will take two inputs from a user; a first name and a last-name. Then it will display the values to the user, updating as the user types.

First, create a simple HTML page. Then import the Angular library:


<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js" ></script>

Then create another script block, with a module and controller:


<script>
var watchTest = angular.module('WatchTest',[]);

watchTest.controller('watchTestCtrl',['$scope', function($scope){
}]);
</script>

Inside the controller, add some scope variables. One for the first name and one for the last name:


$scope.firstName = "Jeffry";
$scope.lastName = "Houser";

I'm also going to add a reset function:


$scope.onReset = function(){
$scope.firstName = "";
$scope.lastName = "";
}

The HTML behind this application will put the ng-app tag on the body, and point the watchTestCtrl on the div tag:


<body ng-app="WatchTest">
<div ng-controller="watchTestCtrl">
First Name: <input type="text" ng-model="firstName" /><br/>
Last Name: <input type="text" ng-model="lastName" /><br/>
Hello: {{firstName}} {{lastName}}<br/>
<Br/>
<button ng-click="onReset()" >Reset</button>
</div>
</body>

See this app in action or play with the Plunker.

Setting up a Simple Watch

AngularJS binding, with ng-model and the double curly bracket syntax, does not allow you to run JavaScript code when a value changes. Thankfully, it does provide a $scope function, $watch(), for this purpose.

Let's set up a simple watch to show how we can run additional code when values change.

Inside the controller, add the watch:


$scope.$watch( 'firstName',
function(newValue, oldValue){
console.log('firstName Changed');
console.log(newValue);
console.log(oldValue);
}
);

$scope.$watch( 'lastName',
function(newValue, oldValue){
console.log('lastName Changed');
console.log(newValue);
console.log(oldValue);
}
);

The $watch() is a function on the $scope service. It accepts two arguments. The first is a string, representing the value that you want to watch for changes. This could also be a function that returns the value you want to watch. The second is a function which is executed whenever the value changes. The arguments for the change function are the newValue and the oldValue.

For the sake of the example, I just logged the new and old values to the console; however you could perform other functionality, such as instigating a remote service call or other processing.

You can try to run this app or play with the Plunker. You'll need to keep the web developer console of your browser open to see the log statements.

The problem with Binding and Asynchronous calls

For binding, or the $watch() method, to execute the variable change must happen within the context of an AngularJS $digest(). Angular automatically runs $digest() whenever user interaction takes places which affects the $scope. However, the $digest() will not occur without user interaction. When retrieving, or changing, data asynchronously, the $digest() will not be triggered, the bindings will not update, and the $watch() method never fires.

To demonstrate the problem, I am going to use the JavaScript setTimeout() function instead building out a full remote service call. First, I'm going to add a JavaScript method to change the firstName with the setTimeout() function:


$scope.triggerChange = function () {
setTimeout(function(){
console.log('First name being reset');
$scope.firstName = '';
}, 1000);
};

I'm also going to add a button to trigger that change:


<button ng-click="triggerChange()" >Trigger Change</button>

So, when you click the "Trigger Change" button in the UI; the triggerChange() method will be executed, queuing up the timeout function to run in 1 second. When it runs, we see a console.log() and the value is changed. Try this and you'll see that the values in the UI are not updated even though you can see the log in the console, proving that the element did execute.

As a helper, you can add a method to log the user information:


$scope.logName = function () {
console.log($scope.firstName);
console.log($scope.lastName);
}

And add a button to trigger this:


<button ng-click="logName()" >Log Name</button>

Click the logName button, and you'll see that the values in the UI automatically get updated. This is because the user interaction forced the $digest() method to execute, which updated the bindings, and also caused the $watch() function to execute.

You can Test the app or play with the Plunker

Forcing the update with $apply() method on $scope

The simplest solution to this is to use Angular's $apply() method on the $scope. The $apply() method accepts a single argument, which is a function. The function executes, then the $digest() functionality will be executed for the variables that changed. We can change the trigger function, like this:


$scope.triggerChangeWithApply = function () {
setTimeout(function(){
console.log('First name being reset');
$scope.$apply(function(){
$scope.firstName = ''
}
)
}, 1000);
};

Instead of changing the $scope.firstName directly in the timeout function, it is done inside he $apply() function. The $apply() function makes sure that Angular's bindings update. Retest the code, and you'll see that after the timeout function runs, the UI is automatically updated. Play with the Plunker

What do you do when all your code is encapsulated into an Angular Service?

The original use case I mentioned was when a remote service responded with asynchronous events. If you're building a larger application, there is a good chance that your remote service code will be encapsulated out of a controller and into an AngularJS Service. AngularJS Services do not have access to a $scope service because they do not have a view. As such, you cannot directly use $apply() to update bindings. What do you do when you want to update the view in response to an event handler inside of an Angular service?

I have two solutions, and I'm not sure which is better. The first is to add a callback to the function which resides inside the controller. Pass the callback as an argument into the service, and execute the callback when you get results. The callback method can call $apply() on the $scope. Something like this would work:


var callback = function(){
$scope.$apply()
}

In this case, a function is not used as an argument to $apply(). Angular will automatically figure out everything that has changed. The second solution is to grab a UI Element and find the scope on that, something like this.


var element = angular.element($('#MyElementWithController'));
element.scope().$apply();

This method works, and prevents the need for a callback just to update, however I'm unclear if it is the best approach. Ideally you wouldn't want the services trying to access the HTML directly for any reason.

Final Thoughts

I've had a lot of fun with this; but

Did I mention that you should all check out the free AngularJS training books I wrote at training course on AngularJS? You can get some books I wrote for free.

Sign up for DotComIt's Monthly Technical Newsletter

Calling a ColdFusion CFC from AngularJS

I have been working on my HTML5/AngularJS book and ran into a problem integrating AngularJS with ColdFusion. I wanted to be able to reuse the same ColdFusion services in my Angular project as they did with my Flex project. This didn't work quite as elegantly as I thought, so I thought I'd blog about the problems, and my solution.

Setting up the CFC

ColdFusion allows you to easily create a web service inside a CFC. Each method can be set with an access of remote and that makes the method available to AMF, SOAP, and REST calls. The AngularJS code will use REST. I put together a simple CFC for demonstration purposes:

<cfcomponent displayName="TestService" hints="I am a Test Service for an AngularJS Article">
 <cffunction name="sum" returnformat="plain" access="remote" output="true" hint="I am a Sample CFC" >    
  <cfargument name="num1" type="numeric" required="true"  />         
  <cfargument name="num2" type="numeric" required="true"  />         
  <cfreturn arguments.num1 + arguments.num2 />
 </cffunction>
</cfcomponent>

The CFC starts with a cfcomponent tag.  It has a single method inside of it, named sum.  The sum method accepts two numeric arguments, adds them together, and returns the result.  This is pretty simple. 

A ColdFusion Sample for creating a Post Call

There are two ways to call a CFC method as a REST service, either through an HTTP get call or an HTTP post call.  This is well documented in the ColdFusion docs. The problem with get approach is that all the values are put in the URL; and URLs have a character limit depending upon the browser. As such, I prefer to make calls using an HTTP post.  The name of the method and the arguments must be specified as form parameter in order for ColdFusion to determine how to process the call.

Here is a sample ColdFusion template to test the call:

<cfhttp url="http://#cgi.SERVER_NAME#/com/dotComIt/samples/callingCFC/TestService.cfc" method="post" result="results" >
                <cfhttpparam name="method" value="sum" type="formfield">
                <cfhttpparam name="num1" value="1" type="formfield">
                <cfhttpparam name="num2" value="2" type="formfield">
</cfhttp>
<Cfdump var="#results.filecontent#" />

This uses the CFHTTP tag to make the remote call.  It specifies three separate form fields:

  • method: This is the name of the method to call on the URL, named sum.
  • num1: This is the first argument value of the CFC’s method, and it is hard coded to the value 1.
  • num2: This is the second argument value into the CFC method, and it is hard coded to the value 2.

If you run this template, you'll see that you get a result of 3.0 displayed to the screen.  So, we have created a CFC and proved the method can be executed using an HTTP Post call.  The next step is to make this call from AngularJS.

Setting up the AngularJS App

To make a post call from AngularJS, you can use $http.post(), which is a helper function to make post calls easier.  Before we jump into that we’ll need to set up our Angular app.  Start with a simple HTML page:

<html>
<head>
    <script src="/AngularApp/js/libraries/angular.js"></script>
</head>
<body ng-app="testCalls">
</body>
</html>

This page imports the Angular framework and creates a single app; named testCalls.  Start another script block in the header and use it to define the application.  We'll be putting more JavaScript in this block later:

<script>
 testCalls = angular.module('testCalls', []);
</script>

Next, we'll need a div for our content:

<div ng-controller="testCallsCtrl">
</div>

The content is just going to be buttons that trigger calls to the remote service and display the results.  The content will be filled in shortly.  Create the controller in your JavaScript block:

function testCallsCtrl($scope, $http){
}

For now the controller is empty.  If you load your app in a browser, and check the console you should see no errors yet, but you also have no functionality.

Calling the Service with a Parameter object, and why it didn’t work

Most of the documentation I read about AngularJS has people making post calls and sending an object as the parameter, so that was my first approach.  First, add the button to the HTML Div:

<input type="button" value="Sum Via Post Object" ng-click="onPostObject()" />
<b>Post No Header Result</b>: {{postResultObject}}<br/>

This HTML Snippet will call the function onPostObject(), and through the use of binding display the results from the postResultObject variable. 

In your controller code, create the result variable:

$scope.postResultObject = 0;

Next, create a function to make the call:

$scope.onPostObject = function onPostObject(){<br />
}

Create an object to contain the three parameters:

var parameters = {
 num1 : 1,
 num2 : 2,
 method   : "sum"
}

This parameter object contains the method, sum, and values for the two input parameters to the method: num1, and num2.  As with our ColdFusion sample, both num1 and num2 are hardcoded values.  This is done for simplicity purposes of this sample.

Finally, use the $http.post() method to call the remote service:

$http.post('/com/dotComIt/samples/callingCFC/TestService.cfc', parameters).success(onPostObjectSuccess).error(onError);

The first argument of the post method is the endpoint of the service to call. In this case, it calls our TestService.cfc.  Then the parameter object is added.  On a success response from the server, an onPostObjectSuccess() method will be executed.  If the server has an error; then the onError() method is called.

The onError method is re-used for all our subsequent examples, so this is it:

var onError = function onError(data, status, headers, config){
 console.log('failure');
 console.log(data);
}

It simple logs the data to the console.  In a real app you would want to display information to the user, but that Is not needed here.  This is the onPostObjectSuccess() method:

var onPostObjectSuccess = function onPostObjectSuccess(data, status, headers, config){
 console.log('success');
 console.log(data);
 $scope.postResultObject = data;
}

This logs the returned data to the console, and uses it to set the controller’s postResultObject variable, which will in turn update the display.

If you set this up and try to execute, you will get unexpected results returned from the server. 

Instead of the number 3, you’ll see a bunch of HTML.  The ColdFusion server does not the parameter object as individual form variables, instead they are sent as a single object.  Since there is no method variable, ColdFusion does not try to execute the service method, but instead tries to load the CFC, which redirects to an Administrator login page.  The HTML of the login page is what is returned.

For comparison’s sake, this is what is shown in ServiceCapture for the call:

The ‘text’ is sent as one big JSON object.  That is not what we want.

Calling the Service with a Query String, and why it didn't work

The next approach I tried was to send the parameters along as if they were a query string.  First, let’s add the UI elements, the button and the place for the header:

<input type="button" value="Sum Via Post String" ng-click="onPostString()" />
<b>Post No Header Result</b>: {{postResultString}}<br/>

Back to the JavaScript block, and add the variable to hold the results from this:

$scope.postResultString = 0;

Next create the onPostString() method:

$scope.onPostString = function onPostString(){
 console.log('onPostStringNoHeader');
 parameters =    "num1" + '=' + 1 + '&'
 parameters +=   "num2" + '=' + 2 + "&"
 parameters +=   "method" + "=" + "sum" ;
 $http.post('/com/dotComIt/samples/callingCFC/TestService.cfc', parameters).success(onPostStringSuccess).error(onError);
}

The code uses string concatenation to create a parameter string, which will look like 'num1=1&num2=2&method=sum'. This is very similar to using a Query string.

The onPostStringSuccess() method just outputs the results to the console and updates the postResultString variable:

var onPostStringSuccess = function onPostStringSuccess(data, status, headers, config){
 console.log('success');
 console.log(data);
 $scope.postResultString = data;
}

If set this up and try it, the same thing will happen:

This is the same problem we previously saw.  ColdFusion doesn’t see the method name in the request and tries to launch the CFC in the CFC Explorer.  The page returned is asking for an administrator login.  This is the ServiceCapture information:

Although, we can see our parameter string as part of the call, there are no formal parameters attached to it; so ColdFusion can’t determine how to handle the call.

Calling the Service with a Query String, and getting expected results

The problem with the two previous calls is that the parameters are not being added to the call with the correct content type to create, what is essentially, a form post.  To solve this, we’ll need to specify the appropriate header.  First, add this to your HTML:

<input type="button" value="sum Via Post String w/ Header" ng-click="onPostStringWithHeader()" />
<b>Post Result With Header</b>: {{postResultStringWithHeader}}<br/>

This code snippet will call a method on the controller, and then display the results.  It works just like our previous two samples.

Create the postResultStringWithHeader variable in the Angular Controller:

$scope.postResultStringWithHeader = 0;

Next, create the method for making the remote call:

$scope.onPostStringWithHeader = function onPostStringWithHeader(){
 parameters =    "num1" + '=' + 1 + '&'
 parameters +=   "num2" + '=' + 2 + "&"
 parameters +=   "method" + "=" + "sum" ;
 $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
 $http.post('/com/dotComIt/samples/callingCFC/TestService.cfc', parameters).success(onPostStringWithHeaderSuccess).error(onError);
}

This code is almost, identical to the previous approach.  The most important change is that it sets the header for the HTTP calls to ‘application/x-www-form-urlencoded’.  This is the secret sauce that made the remote calls magically work.  This is the result method:

var onPostStringWithHeaderSuccess = function onPostStringWithHeaderSuccess(data, status, headers, config){
 console.log('success');
 console.log(data);
 $scope.postResultStringWithHeader = data;
}

The result method displays the returned data to the console and stores it for display in the HTML template.

These are the successful results, displayed in the browser:

This is the request from service capture:

You can see that this request has a formal parameter tab as part of the call.  When this request gets to the server, ColdFusion is able to correctly discern the request and determine which method should be called and how to handle the parameters.  We have achieved success.

Final Thoughts

A more in depth solution to what is going on under the hood is written up here. It also provides additional details on handling arrays and objects, which are important to many aspects of development.  I have spent a couple days researching the different methods to communicate between Angular and ColdFusion without rewriting code, or adding JQuery Dependencies, and this has been the most elegant.

Sign up for DotComIt's Monthly Technical Newsletter

How to Fail Fantastically: My 360|Stack Session Results + Video

At 360|Stack I gave a presentation entitled "How to Fail Fantastically" session results. I recently got the results from my survey. Only three people provided results this time; and there was only one comment.

I got two 5 ratings and one 4. I assume the ratings are out of 5; so that is pretty good. There was one comment left:

A very good presentation of things to watch out for if you want to run your own company, or for almost any venture you want to be a part of.

The comment is pretty complimentary. I do notice that since the went digital in their session survey's the ratings are fewer, as are the comments. I think people are less likely to type long comments into a smartphone.

And I promised a video, so you can view the presentation here.

Why You Didn't Hire Me

I started writing this post a few years ago; after I failed to come to terms with a new client. I finished it for September's Flextras/DotComIt newsletter. I realized that I seem to pass on more opportunities than I take on. Part of the problem is me, of course, because I can be picky about the type of work I take on. But, there does seem to be a common thread running through these rejections. This newsletter collects my thoughts on why I wasn't a fit for the project you wanted to hire me for.

How I Work

Before going into why we didn't come to an agreement, I thought I'd explain how I usually work. There are usually two different approaches I can take to a project contract: either by the hour, or by the project. I'll explain a bit about each approach.

By the Hour

Working by the hour means that the client pays me for each hour I work for them. This includes everything from meetings, email management, documentation, system maintenance, and writing code. Some important aspects of an hourly contract:
  • They are great if a client wants to get me in the door to have me start working as quickly as possible.
  • They are very flexible and allow for a constant change in requirements, priorities, and focus. This is good for the client because it allows for a fluid approach to development.
  • The deliverables are delivered when they are ready, and functionality usually comes in small, quick chunks.
  • If the client wants to manage me as one of their resources, then this is the way to go. Usually we have weekly planning session to discuss the progress made and the plan for the week. I expect that the client is involved every step of the way; and will direct where my efforts should go. This gets a very tight feedback loop and the client and problems can be addressed quickly.
  • The client can terminate at any time, usually with minimal commitment.
  • The client is responsible for managing the budget and schedule; and none of the responsibility is passed onto us. I will provide a client with weekly breakdowns known as time sheets that they must approve.

Some of these items are considered 'double edged' swords. The fluid nature of development means we often code for speed and not architecture elegance. It is tough for the developer to budget our time and finances without said commitments. Some clients are more comfortable by limiting their own commitment.

By the Project

Working by the project contracts usually means with a fixed fee. The client hires the developer for a specific period of time for a specific amount of money to complete a specific scope of work. Some aspects of a project contract are:

  • They are great for a client working within a fixed budget or under a deadline. This is also good for both the developer, who gets guaranteed work and the client who gets a guarantee on the project being complete in their limitations.
  • The budget is all inclusive, which means every aspect of our time is included in the budget.
  • A project plan is created, which will include fixed milestones with detailed descriptions of functionality. The down side of this is that this requires a lot of paperwork up front in order to define the scope. Sometimes it is hard for a client to create the documentation in enough detail needed to code something.
  • Changes to the focus or priorities can be very costly; and require additional paperwork. When changing a fixed fee bid; we have clients sign a change request that includes a description of the changes, the additional cost, and the new timeline.
  • We act as the project manager and balance our own time, budget, and development tasks against project milestones. This relieves the client of some responsibility, but the client usually gets more functionality in a single deliverable than they would in an hourly contract. Milestones are often 2-8 weeks apart.

A lot of developers don't like working on fixed fee bids; and I can understand why. The requirements are very rarely carved in stone and often change. It is tough to manage those changes in the context of a project bid. I, personally, love fixed fee projects because, like many small business owners, I like to look out at least three months ahead to see that we have a plan.

Reasons we Couldn't Come to Terms

Understanding the two approaches that I can take to project development, here are some of the reasons why I often don't come to terms:
  • No Contract: Some clients have insisted that we work without having a contract in place. A contract will define the terms of the full relationship including payment terms, code ownership, lawsuit liability, termination terms, and what one party can do if the other party is in default. I like to have the contract in place to avoid any ambiguity. In my early days it was to make sure I could get paid. These days, it also makes sure they can't claim ownership on work I do not do for them.
  • Intellectual Property Rights: Ownership of the project's output is a big deal for many companies. They want to make sure they own the project and source code, and are able to maintain it without coming back to us. They also want to make sure that the source code I provide them is not violating the IP rights of any other organizations or developers. This is all fine. However, I have seen IP clauses are too over-reaching for my tastes. I am very careful not to transfer ownership to the client of anything I do not build for them. I maybe building something for other clients; or I may be writing newsletters like this one, or I may be creating podcasts, or creating for my own projects, such as Flextras. I am very careful not to transfer ownership of everything I create.
  • Work with Jeffry Houser, not DotComIt: I've lost projects because I only work through DotComIt. Some people insist I must personally sign contracts as an individual instead of as a representative of DotComIt. I never do that. Issues such as insurance, liability, and accounting all go through DotComIt. As a compromise; I may suggest a 'key person' clause to the contract which says I will be the primary contact, or developer, on a client's project.
  • Mixing Project types: I don't like it when a client tries to mix our two approaches to development; and I'm undecided if that is me being inflexible or not. I have had clients request explicit deliverables in an hourly contract. Sometimes hourly contracts includes a limit on the amount of hours worked; so a list of deliverables could put me in a position where I am contractually obligated to complete said deliverables without pay. I do not want to be in that situation. Likewise, I have had clients request an hourly breakdown in a fixed fee project. I understand the client doesn't want to pay me for time I am not working, but in such cases, they should focus on the bottom line, functionality, and delivery dates. The micromanagement gives me a pause.
  • Non-Compete: I understand that a client doesn't want to hire me and then have me steal their client list, or source code, and use it to help, or become, a competitor. However, some non-competes are more far reaching than that. In one contract, with a web development firm that wanted to subcontract work out to me; a clause said I couldn't work in a similar industry. I feel every client I had before and after them would have violated that clause. Another contract had a guarantee I had not worked for any of their clients two years prior to signing. Without their client list; how could I make that promise? I'm fine with a company protecting their proprietary information, but I'm very careful not to sign away my right to continue to do what I do.
  • No-Advance: I always like to ask clients for an advance at the start of the project. Some clients insist on not paying anything until they have the final results, and that is a red flag for me. I do not want to spend weeks, or months, building something only to find out the client can't, or won't, pay. For fixed fee projects; I am usually able to successfully negotiate some type of an advance. For hourly projects, I am not always so lucky.

Any contract with a client will have a dozen different little things that will cover the working arrangement with the client. Usually many of these things are no-issue or easily dealt with, but the items above are the main reasons why I often walk away from a contract.

Final Thoughts

I'm curious to hear about experiences of others. What are some of the problems you've had when working with clients? At what point do you decide it is time to pass on this client and move on?

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.