Looking back at some of the angular code I have written in an older project, I decided to document some of the thoughts I had at the time when writing said code. Remember, this was all before John Papa’s Guide was popularized (or even created?). There are conventions now that the majority of developers have agreed on that are different than what I am describing below.


Exposing data from Controller to View

The way Angular 1.x shares data between a controller (.js) and a view (.html) is through the use of a $scope variable. Most tutorials on the internet demonstrate the power of data binding via $scope, but the code they use in their demonstrations are often short. When an angular code base begins to grow, a mistake seems to be letting the $scope variable run rampant.

It is important to remember that the main reason we use $scope is to expose data from the controller to the view. This means that the $scope should only be used once for binding and never as a proxy to another object.

Example of “bad” $scope usage

$scope.importantFunction = function() {
    // do something
};

// Some logic here, then call the function
$scope.importantFunction();

// Some more logic, call the function
$scope.importantFunction();

// Maybe inside a watcher?
$scope.$watch('prop', function() {
    // ....
    $scope.importantFunction();
});

Notice how $scope is used as a proxy to “importantFunction”. Yes, it exposes importantFunction to the view, but do we need to access importantFunction via $scope every time?

Example of “better” $scope usage

importantFunction = function() {
    // do something
};

// just call it
importantFunction();

// ... more logic, then call it
importantFunction();

// Inside the watcher
$scope.$watch('prop', function() {
    // ....
    importantFunction();
});

$scope.importantFunction = importantFunction;

Here we access importantFunction directly. The code above only ever uses $scope for $scope specific tasks (watcher and exposing data).

Tracking Application State

Mutating Data

One issue with sharing data between controller and view is the fact that they are two way bound. When data is bound to $scope, is there an easy way to determine what accesses it? Is a particular piece of data intended to be view only (one way bound?) or does the view mutate the data? Again, many tutorials on the internet gloss over these details and only shows you the upsides of two-way binding. “Two way binding is magical! It ‘just’ works”. Except every engineer knows that magic might not always be a good thing.

Although there is really no good way to track accessors of two-way bound data, a convention was initially conceived for easier debugging. Most data changed by the view is due to the “ng-model” directive. The ng-model directives two way binds (often to an input element) to some data stored on $scope. Because of this aspect, the convention is to create a “models” object in the controller that acts as a proxy. Any data that needs to be mutated by the view will be bound to a property on models.

Example

// Controller
var models = {
    user: {
        name: '',
        password: '',
        role: ''
    }
};

$scope.models = models;
<!-- view -->
<input type="text" ng-model="models.user.name" />
<input type="password" ng-model="models.user.password" />
<select ng-model="models.user.role">
    <option value="">Role 1</option>
    <option value="">Role 2</option>
    <option value="">Role 3</option>
</select>

Through this convention, we easily know that properties of “models” can be changed by the view while everything else should be read only.

Doing databinding this way also eliminates the need to worry about two-way binding with immutable/primitive types. You can find out more about two-way binding pitfalls by googling “two way binding angular problem”.

Here is the first result as of right now. http://juristr.com/blog/2014/11/learning-ng-databinding-doesnt-work/

Application State

Application state is represented in the UI using built in directives that act on conditionals. Ng-show, ng-hide, ng-if, ng-switch, ng-class … are all examples of such directives that render certain things at certain times based on conditionals. These constructs allows for very powerful and complex UIs to be built quickly and easily. However, they can also become a pitfall as an application begins to grow. One should question whether or not it is a good idea to embed so much logic in the presentation layer. Is this not the reason why people advocated for separation of concerns? You can, but should you really be embedding business logic inside your views?

Example: Is code like this acceptable?

<div ng-if="user.name != '' && user.password != '' && user.role != ''">
</div>

What we’re trying to accomplish is to validate that all fields are filled before showing the div. What we ended up doing is writing an ugly expression. Wouldn’t it be nice if we could just show the div when fields have been filled out?

<div ng-if"validFields()">
</div>

In our controller we would have the function “validFields” return a boolean. We can even add more complex logic (like input validation) without polluting the view.

Note: this is not even the best way to do this. Using built in angular validators and ng-form would be the way to go, but in my opinion, this approach is still way better than writing out that ugly expression and is a lot more readable.

Because so many things in the views are toggled by these conditionals, a final convention I developed in this project was to declare a “status” object in the controller that is used to track all state on the page. In hindsight I think “status” should have been called something else (maybe state?). The idea is to have a centralized object that represents the state of the page.

Example

// controller
var status = {
    loadingSpinner: false,
    isValidUser: false
};

var validateUser = function() {
    status.isValidUser = (
        models.user.name !== '' &&
        models.user.password !== '' &&
        models.user.role isnt ''
    );
};

$scope.status = status;
<div ng-if="status.isValidUser"></div>