Brian Vander Plaats

Developer

Blog

13 Jul 2016

AngularJS Complex Edit Page

This article demonstrates a “complex” edit page in Angular. I’ve created a demo page using JSFiddle.

So what makes an editing page “complex”? In my experience complexity begins whenever you have two or more non-lookup entities on a single page or view. This is primarily due to issues regarding state, foreign key management, and additional bindings. The most common scenario is with the parent-child (master/detail) relationship. In this example I model a common product pattern with model-sku. For many products it is typical to have a basic model that comes in a number of different configurations and sizes. It is important that we can uniquely identify a specific product size for sales, shipping, and inventory purposes. At the same time, we want to group related part numbers together under a common “model” so that they can share descriptions, images, pricing, categories, etc.

Other common parent-child relationships

  • Sales Header -> Sales Detail
  • Purchase Order Header -> PO Detail
  • Formula / Assembly -> Bill of Materials / Recipe Items
  • Employee -> Time / Punch/ Hours history
  • Location/department -> Employees
  • Vendor -> Vendor Contacts

Page Structure

The core structure of the page is similar to the Simple Edit Page. The flexiblity of JSON objects to contain arrays of objects makes binding much simpler. We simply need a reference to $scope.model, and optionally $scope.modelPrior. The part numbers are stored as an array of objects here $scope.model.partNumbers. Binding this inside the view is simple, via ng-repeat="partNumber" in model.partNumbers" Once again the beauty of this approach is that we can operate on model without direct knowledge of how the view renders each part number. For example, deletePartNumber() simply removes a part number from the array. It doesn’t need to do a DOM lookup for that row and remove markup - we just adjust the data and angular re-binds the table (instantly I might add).

There is some work to do with managing the detail records.

  1. We need to add an empty line at the bottom for adding an additional record
  2. We need to assign temporary key values to new items
  3. We need a way to remove records and keep track of removed records

The most important principle with parent-child relationships is that all changes made should be atomic. A simplistic system might implement separate db/service calls for editing individual records, but this doesn’t allow the user to makes changes, then change their minds and cancel. It also creates the problem of partial updates because of system issues. What if the user enters invalid data into the 20th row of a detail screen, causing the system to crash after processing the previous 19 records? With Angular data binding this is pretty easy to avoid, at least at the client level (the service layer still needs to consider transactions).

Adding Detail Records

There are two general approaches for creating a new line row. First, we can simply add a new, empty partNumber to the model.partNumbers collection. I don’t like that approach however, as it complicates the binding in the ng-repeat section. Additionally, when we go to persist the model, we will either need to strip out the blank row, or the service layer will need to check for blank values. The second approach is to add a <tr> below the ng-repeat, and create a placeholder object for binding, newPartNumber. On page load or when the user clicks the add button, newPartNumber is loaded with blank values.

It is also important to assign a temporary key to the part number. This serves two purposes. One, it signals to the business layer that these are records that need to be inserted, and secondly it gives us a handle for removing the new record.

Removing Detail Records

As mentioned earlier, removing a part number is as simple as removing it from the array. To do this, we place a delete button on each row. The delete button will reference the deletePartNumber() function. Angular binding is quite elegant here. Each ng-click references the part number to delete via databinding:

<button class="editButton" ng-class="pageMode" ng-click="deletePartNumber(partNumber.partNumberId)" ng-show="partNumber.flagCanDelete === true">Delete</button>

However, we should also consider when it is appropriate to remove a part number. A good rule of thumb is that an entity can be removed if it hasn’t been used as part of another relationship - i.e. the part number has not been sold, purchased, etc. To simulate this, I’ve marked some of the part numbers as not eligible for deletion. The ng-show above takes advantage of this and hides the delete button. Remember that the service layer should also enforce this rule - this is just a UI convenience.

Validation

Both the model and part number areas are part of the same <form>, the advantage being that the save operation can check a single global $valid state. For this example I’ve put required attributes on several of the part number fields. When these are empty, the form state is updated to be invalid, which in turn disables the save operation using ng-disabled

Conclusion

I was pleasantly surprised to see how straightforward a parent-child relationship can be implemented in Angular.

03 Jul 2016

Migrating to Jekyll Github Pages

As of yesterday my blog is being hosted by GitHub Pages, using the Jekyll static page engine. I’ve been using Wordpress hosted on a DigitalOcean droplet for the past year, and I haven’t been happy with the platform. Stability was a major concern, and the blog authoring didn’t suit technical blogging very well. And finally, Github Pages + Jekyll has some seriously cool features.

Wordpress Stability

Over nine months, my site was down for at least twice a week. Not cool. As best as I can tell, my instance was running out of memory, which is ridiculous for a low traffic site…

Error Establishing Database Connection

ugh.

Initially I was very exicted about using WordPress. DigitialOcean uses the concept of “droplets”, that can be loaded with a number of Linux server configurations. I chose the $10/mo option, which gave me 1GB memory, 1 processor core, and a 30GB SSD. Surely enough for a personal blog? Unfortunately, within a month or two of running the new site, it started going down, frequently.

The first thing I noticed was a large number of “xmlrpc” attacks

XML rPC Attack

The XML rpc service is used to upload posts to wordpress from clients. As best as I can gather, these requests were flooding the server to the point that memory utilization was over 99%, taking out MySQL (not really sure why). My initial response was to enable the firewall ufw, and add each attacker to the list. I did consider disabling the xmlrpc service, but I didn’t feel great about removing a feature that I may want to use in the future.

Manually updating the firewall wasn’t very effective however, as the IP’s frequently change, and I have no warning of when it starts happening. So my next step was to install fail2ban. I configured fail2ban to block attackers after 3 failed attempts of calling the xmlrpc service. This was a much better approach, as I didn’t need to monitor the site, and my IP banned list wouldn’t grow very long (fail2ban reverses the ban after a period of time). But that still didn’t work. I mean, it was better, but my site was still going offline.

I considered adding more memory to the instance, but I felt that paying another $10 / mo for 2GB of memory was too much for a personal site. I learned that the swap file is disabled in DigitalOcean’s linux configurations, so I enabled it with 4GB. This helped some, but my site was still going offline at least once a week - and the swap file wasn’t even full!

At this point I was simply fed up with the platform, and not sure what to do next. I set up the blog for blogging, not dealing with attackers / server performance issues!

Wordpress Editing

I was also getting fed up with writing technical articles in Wordpress. My initial Idea was simple:

  1. Research Article, taking notes in Google Docs, creating code samples, etc.
  2. Outline the article in Google Docs
  3. Write draft of article in Google Docs
  4. Upload the draft into Wordpress and update the final draft.

This didn’t work as seamlessly as I would have liked. First, there is no way to directly upload from Google Docs. There used to be a feature for this, but it was removed a few years ago. So I ended up doing a lot of copying and pasting. For the plain text content this wasn’t too bad, but it was a small nightmare for code. In addition to frequent indentation issues, the wordpress editor frequently rewrote code like this: List<string> into: List&lt;string%gt; not cool.

Jekyll

A few months ago I ran into a blog that used Jekyll + GitHub Pages. The initial feature that really turned me on was that the entire blog was hosted in a GitHub repo! Editing is done in MarkDown, in your editor of choice Visual Studio Code is a great choice for this as it has a built-in MarkDown preview mode.

Visual Studio Code Editing

Compared to WordPress, the killer feature of Jekyll is that there is no database! The site contents are all compiled into HTML during deployment, so the server only needs to serve HTML files - no server side rending per page request! The other benefit to this is that GitHub can apparently host these sites very cheaply, because GitHub Pages is free! And in the event I need more that what GitHub provides, I can deploy a Jekyll instance with most cloud providers (including Digital Ocean).

The only problem with Jekyll is that it isn’t extremly easy to set up a site. There are existing sites / layouts available, but they are nowhere near as easy to set up as say a WordPress theme. This is a small tradeoff though, as once the site is up and running you shouldn’t need to touch many configuration details. All told, it took me about 10-15 hours over the last two months to migrate my site.

An invaluable tool was Ben Balter’s Wordpress-to-Jekyll-Exporter. This easily converted all my WordPress posts to MarkDown files, and even kept the correct image links. The code snippets were a bit off, but that wasn’t a big deal to fix. It doesn’t fully convert to Markdown, as my posts still had several <spans>’s in the content, but this was way better than rewriting every single post…

List of Resources for Setting up a Jekyll Blog

Conclusion

I really wanted to like WordPress, and I do think it has it’s place. But for a small developer site, it really isn’t worth the effort needed to keep it running. Granted I could use wordpress.com as my host, but then I still have authoring issues.

On a postitive side, I learned a lot about Linux administration. It was actually kind of fun for a while - I’d see my site down, restart, and it would be down again within minutes (at the worst point). This involved a furious scramble trying to figure out WTH was going on - and lots of on-the-fly learning.

It’s also a good reminder for developers in general that you should assume that anything you put out there will be attacked. Of course, using a popular package with well-known attack surfaces doesn’t help, but you should always assume that some malicious person/bot is going to find your site, and will try to harm it. So you need to be prepared, and leaving things up to your friendly admin / ops staff is not a good strategy.

20 Jun 2016

AngularJS Simple Edit Page

This article demonstrates a simple edit page in Angular. I’ve created a demo page using JSFiddle that implements the following:

  • Binding a single entity to a set of HTML form inputs
  • View and Edit modes - hide the input fields in view mode
  • Buffering model values so that changes can be discarded if necessary
  • Using filters to format display values
  • Basic validation techniques
  • Use of ng-submit vs ng-click

Databinding

Databinding is very straightforward. We store the current entity data in $scope.manufacturer, and then either set ng-model on the inputs or use the databinding `` markup. Changes to the inputs are (by default) immediately reflected in the model, and likewise changes to the model are immediately reflected in the inputs and other bindings. For the state dropdown, we use the lookup service to retrieve and bind the list of states.

A common pattern for data entry pages is to have both a view mode and edit mode. This is accomplished with a set of dynamic css classes on each of the related controls. To hide controls, we set display:none, which allows the control to be in the DOM but take up no space, as opposed to display:hidden

Most data entry pages will also contain the common CRUD operations - which we implement here except for deletion in the manufacturerController:

  • editManufacturer()
  • newManufacturer()
  • saveManufacturer()
  • cancelEdit()

These functions are responsible for setting the current editing mode, and managing the manufacturer buffer / binding. We don’t interact with the DOM except through the model. Notice in saveManufacturer() we check if the manufacturerForm is valid before saving. The form and its collection of bound values are added to the $scope by Angular, so we do not have to look up in the DOM. Last, look at the use of angular.copy(). Remember that $scope.manufacturer contains a reference to a JSON object. If we want to revert it back to the original values, we need to copy the values from $scope.manufacturerPrior. If instead, we set $scope.manufacturer = $scope.manufacturerPrior, we will have two members pointing to the same object, which isn’t what we intended. There will be a subtle error if we go in and out of edit mode. The first time, it will work as expected, since there are two separate objects, but the second time, the form controls will be bound to the same reference that $scope.maufacturerPrior holds!

Filters

In angular, filters are used to manipulate displayed data, either to supress data or to format data. In this example we use a filter to format currency and phone numbers. The currency filter is quite simple, simply specify the filter expression in the binding:

<span class="displayValue" ng-class="pageMode">{{manufacturer.creditLimit | currency}}</span>

Currency is one of a few default filters available in Angular. Others include:

  • number
  • date
  • json
  • lowercase
  • uppercase

Unfortunately these filters don’t work on input fields. To format data inside an input we will need to resort to custom javascript or find an appropriate library control.

We can also create custom filters, which I’ve done here for formatting telephone number using a sample filter from Stackoverflow. To do this you call the filter function on the main app module:

productManagerApp.filter("telephone", function () {
    return function(telephone){
        if (!telephone)
            return '';
        var value = telephone.toString().trim().replace(/^\+/, '');

        if (value.match(/[^0-9]/)) {
            return telephone;
        }

        ...

        return (country + " (" + city + ") " + number).trim();
    };
});

Here you specify the name of the filter telephone, then define a function that takes an input (bound data flowing through the filter) that returns a string output, in the desired display format. Once this is defined, the filter can be used in bindings as follows:

<span class="displayValue" ng-class="pageMode">{{manufacturer.faxNumber | telephone}}</span>

This allows for very clean usage and keeps the formatting logic out of the controller and view.

Forms and Validation

The edit fields are contained in an HTML form. Normally form submission causes a page postback to the server, but angular supresses this by default, unless the action attribute is specified in the form. Strictly speaking you can develop without forms in angular, but it is still helpful to do so, primarily for validation. Forms and their associated named controls have the following properties defined that can be programmatically accessed:

  • $pristine - set to true if user has not interacted
  • $dirty - set to true if user has interacted
  • $valid - true if the form/control is valid
  • $invalid - true if the form/control is invalid
  • $error - a hash that contains references to invalid items

This allows us to check manufacturerForm.$valid or manufacturerForm.nameInput.$valid.

To submit the form, we set the ng-submit attribute of the form to saveManufacturer(). Interestingly we can simply change the save button to specify ng-click() and call the function directly. However it is better to use the form submission model if possible. Additionally the angular docs warns about using ng-submit and ng-click in the same context.

To prevent saving when validation fails, we use the ng-disabled attribute on the input button:

<button type="submit" class="editButton" ng-class="pageMode" form="manufacturerForm"  ng-disabled="manufacturerForm.$invalid">Save</button>

This will visually disable the button as well as the enter submit action. It is also a good idea to check the valid status in the controller function as well

$scope.saveManufacturer = function () {
    if ($scope.manufacturerForm.$valid) {
        $scope.manufacturerPrior = {};
        $scope.pageMode = "viewMode";
    }
}

A word on button layout - for the ng-submit method to work, the button / input must be inside the form. This is not ideal for layout purposes, as you may want to keep all the action buttons together. However in this example, ng-click does not fire for the edit button while inside the form! There are a few workarounds for this. In newer browsers, you can use the form attribute on a button to trigger a submit from outside the form, but this does not work on IE11. These CRUD functions are too important to not work on IE, so that’s out. There are also a number of ways to trigger the submit via JavaScript, but I wasn’t able to find a reliable/simple one, and is outside the scope of this article anyway.

There are two types of validation on the page. The first uses the required attribute, which is fairly straightforward. To alert the user when they need to enter a required field, we place an error span after the form field, using the ng-show attribute:

<span class="error"  ng-show="manufacturerForm.nameInput.$error.required">Name field is required</span>

By default an HTML5 form will display a warning popup on save, but since we are including custom messages here we can supress this by setting the novalidate attribute on the form.

The second type of valiation is a minlength and maxlength attribute on the account number field. There are two ways to set this, use either the minlength or the ng-minlength syntax. The difference I noticed was that with maxlength, you physically couldn’t type more into the field, whereas with ng-maxlength you were able to type unlimited chars (but the validation still failed if above the max length)

Conclusion

This article demonstrated a simple technique for a data entry form. Angular does an impressive job minimizing the amount of code in the controller needed to support the view and edit behaviors.

14 Jun 2016

AngularJS Search Page

This article demonstrates a basic technique for a search page in Angular. I’ve created a demo page using JSFiddle that implements the following:

  • Angular databinding to a repeating list
  • Using a static JSON object
  • Creating a service for common data
  • Angular filtering
  • Using the angular class directive to apply dynamic CSS

This search page uses an all-at-once search technique where the application loads the entire data set first, then filters the results. This is a simplistic technique, which works for up to a few thousand records. The advantage is that once loaded, the data doesn’t need to be re-loaded when the filters change, which can make the search appear very quick to the user. I do not demonstrate any paging techniques here, and in my opinion, paging is something that needs to go away. Paging as a technique is largely a trick for reducing page bandwidth, and while I agree you can’t just load 10K items onto a page, it seems like many places where paging is used have < 1K records. As a user paging isn’t something anyone really wants. If someone sent you a spreadsheet of customers, would you rather have the list separated into multiple worksheets or one large list? Yet many sites still force the user thru multiple pages to get what they are looking for. Thankfully more sites now are starting to use an “infinite” scrolling technique, but that is out of scope for this article.

Databinding

The data for the search page is stored in a static JSON collection in the main javascript file. In a production application, this would be retrieved by a service call to some API endpoint, but for testing, you will also likely have this as a separate JSON file that can be loaded for your unit tests. This is an extremely powerful technique. It allows us to build out the front-end before the back-end is available, which allows us to prototype and iterate much faster. Even after the back-end is available, the static JSON is still useful for unit testing.

To make the JSON available to the view, we create the controller: searchController and set the directive: ng-controller="searchController" in the view. This allows every child element to have access to the scope of this controller. For simple databinding, we either use the {{}} binding expression or set the ng-model directive, but since we have a list of items we want to databind, we need to use the ng-repeat directive:

    <tr ng-repeat="partNumber in searchResults">
        <td>{{partNumber.modelName}}</td>
        <td>{{partNumber.partNumberName}}</td>
        <td>{{partNumber.inventoryPartNumber}}</td>
        <td>{{partNumber.manufacturerPartNumber}}</td>
        <td>{{partNumber.partNumberStatus}}</td>
        <td>{{partNumber.modelCategoryName}}</td>
        <td>{{partNumber.partNumberListPrice}}</td>
    </tr>

The ng-repeat directive will iterate through each JSON object in the searchResults collection, and bind the {{partNumber.XXX}} expressions.

Simple Filter

Adding a single text box filter is quite simple:

<input type="Text" ng-model="query" />

<tr ng-repeat="partNumber in searchResults | filter:query>

Each time the value in the <input> changes, angular re-binds the list, checking for the value of query in any of the string properties of partNumber, so you can essentially search every column with a single text box. If instead we want to search just a single field, we can set the filter expression as follows:

filter:{partNumberName:query}

Multi-Field Filter

This page also demonstrates multiple search fields, including “does not contain” fields. The neat thing is that you can specify the JSON property directly in the <input>, and still keep the filter expression simple:

<input type="text" id="modelContains" ng-model="query.modelName" class="includeInput"/>
<input type="text" id="nameContains" ng-model="query.partNumberName" class="includeInput"/>

Unfortunately the exclude filter is more complicated. With includes, a blank query value essentially matches everything, so by negating the blank value, you are filtering out everything! I found I needed to supply conditional logic to only apply the filter if the <input> contained a value. Additionally, you need to specify each filter field separately, so it is not as clean as the includes:

<tr ng-repeat="partNumber in searchResults | filter:query | 
            filter: (exclude.modelName.length > 0 ? {modelName: '!' + exclude.modelName} : '') |
            filter: (exclude.partNumberName.length > 0 ? {partNumberName: '!' + exclude.partNumberName} : '') |
            filter: (exclude.inventoryPartNumber.length > 0 ? {inventoryPartNumber: '!' + exclude.inventoryPartNumber} : '') |
            filter: (exclude.manufacturerPartNumber.length > 0 ? {manufacturerPartNumber: '!' + exclude.manufacturerPartNumber} : '') |
            filter: (exclude.partNumberListPrice.length > 0 ? {partNumberListPrice: '!' + exclude.partNumberListPrice} : '')">

Services

The advanced search mode contains two dropdowns for status and category. These come from the lookup service, which highlights how Angular wants you to think about separation of concerns. As you can see in the searchController, we just store the references to the lists retrieved from the lookup service - but we could just as well add these lists directly to the controller. But what happens if we want to include the category lists in another view? We would need to add the list to that controller was well - not good. By using the service, we can inject lookup everywhere it needs to be used. Additionally, at some point we may want to retrieve the category list from a database. A controller should absolutely not make any back-end calls to an API or database, as this involves configuration details that we won’t know until runtime. The controller’s job is to expose data and logic to the view - that’s it. It should be irrelevant to the controller where the data comes from.

Angular Class Directive

Lastly, I demonstrate using the ng-class directive to apply dynamic CSS to the view. In this example, we have two search modes - basic and advanced. We need to hide components depending on the mode. First off, we do not want to do this in the controller! The controller should not touch the DOM at all - it should only operate on and communicate through the scope. Secondly, we want to use CSS classes instead of iterating through DOM elements. Here’s how the operation should look like:

  1. User changes search mode by clicking on link: <a href="#" ng-click="toggleSearch('advancedSearch')">Advanced Search</a>
  2. searchController updates the current searchMode, which corresponds to the CSS class name to activate:
$scope.toggleSearch = function(searchMode) {
         $scope.searchMode = searchMode;
         $scope.query = '';
         $scope.exclude = '';
     }
  1. The three main view elements: searchHeader, searchFilter, searchResults have an ng-class directive, which can apply a CSS class. When $scope.searchMode changes, the classes for all three will be updated. Here is what the classes look like for the searchResults. In basic mode, this div takes up the full row from left to right, but when advancedSearch is active, we need to shift the div over
.searchResults.advancedSearch {
  margin-left:250px;
}
.searchResults.basicSearch {
  margin-left:0px;
}

The power of this technique is that any time we want to add another UI component that behaves differently with the different modes, we merely need to define the appropriate CSS classes for the new component.

Conclusion

While simple, this example provides a basic template for setting up a search page.

16 May 2016

AngularJS Introduction

AngularJS is a JavaScript framework developed by Google for front-end web development. It allows creation of a class of applications known as “Single-Page-Applications” (SPA). A SPA typically loads all required code (HMTL/CSS/JavaScript) in a single page request. In response to user actions, additional resources are loaded as necessary thru XMLHttpRequests / AJAX. There is no postback or transfer of control to another page - to the browser the user is simply sitting on / interacting with a single page. This architecture allows for a fluid, seamless feel to a web application, bringing it closer to what a native application feels like. While network latency is often a limiting factor in performance, traditional web applications exacerbate this by constantly loading/reloading application components, and processing presentation details on the server. In a SPA, shared components are typically loaded once, with page-specific content loading dynamically as needed(often only a few kilobytes).

AngularJS was written specifically for data-oriented applications, which most often refer to line of business applications (LOB). Realizing that a common need was writing data entry forms hooked up to databases, the Angular architecture was optimized for performing data binding operations. Additionally, Angular philosophy stresses strict separation of concerns and testability. It’s no secret that web applications (and business applications in general) are often bloated and buggy,and some of this can be blamed by poor platform architecture. Obviously no tool is going to make up for a poor development approach, but a goal of Angular is to make it easier to write better software for those that care about such things…

An Application Example

Let’s see what an angular application looks like. At the most basic level an application will look something like this:

  • References to the AngularJS library
  • an HTML tag with the ng-app attribute / directive
  • a definition for the main application module
  • html markup with angular bindings
<!DOCTYPE html>
<html ng-app="myApp">
  <head>
  </head>

  <body>
	<div ng-controller="defaultController">
	  <h1>{{greeting}}</h1>
	</div>

	<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.2/angular.min.js'></script>
	<script>
		var app = angular.module('myApp', []);

		app.controller('defaultController', function($scope){
		  
		  $scope.greeting = "Hello, World!";
		  
		});
	</script>
	</body>
</html>

The main components of this application are:

  1. the html file itself, usually index.html. This is the primary page the browser loads.
  2. Angular library reference
  3. A script block (usually in a separate file i.e. app.js) that defines the main application module.
  4. A script block that defines a “controller”. The job of the controller is to provide data to our application
  5. HTML markup containing data binding(s) to the model (defined in the controller).

When this page loads, the application module “myApp” is instantiated in the current browser context, and given a controller reference. Then, the HTML markup is processed to reflect any data changes. It’s important to realize at this point that the page is already “loaded” as far as the browser is concerned. Initially the section <h1></h1> is rendered as `` by the browser. When Angular runs, it sees this as a databinding, and replaces this with whatever value the greeting attribute is on the current scope.

One implication of this is that you can have an Angular “application” pretty much anywhere you can serve an HTML page. For example, you could take a legacy ASP.NET application and replace the search page with an embedded angular application, or you could create an entire website composed of a collection of Angular applications.

Angular Terms

Like any framework, Angular has a number of key terms you should be familiar with:

  • Template - a partial block of HTML that contains HTML and Angular bindings
  • View - The rendered template displayed in the browser - a template becomes a view after Angular replaces the bindings with values
  • Model - The model represents the data that is available to use on the current page.
  • Scope - All angular components access the Model through the scope. What is available in the scope depends on where the element is on the current page.
  • Controller - A JavaScript function that provides data and behaviors to a view. The controller should not engage in any DOM manipulation.
  • Module - A module is a container for the various parts of your application - Defined components must reference a specific module
  • Directive - Directive are HTML attributes that extend the tag with additional functionality, or represent a new tag altogether.
  • Service - Represents common functionality shared by all parts of an application.
  • Two-Way Databinding - The concept that changes to a property of the scope are immediately available to the directive/view as well as the controller.

Angular Concepts

Angular is an opinionated framework - it was designed with certain principles in mind, and it strongly encourages you to follow those.

Separation of Concerns

In Angular, it is very important that components do one thing well, and do not cross prescribed boundaries.

  • Controllers can manipulate the model, add data and behaviors to the scope, but should not directly update the DOM
  • Directives and templates should interact with the model through the properties exposed on the scope. Complex interactions should be handled at the controller level
  • Use Filters to format and massage data, rather than JavaScript blocks embedded in the template
  • Break common template code into directives e.g. Customer Address
  • Take common controller code and place into a service e.g. a list of US states

Dependency Injection

Angular uses the dependency injection pattern to pass services to controllers, filters, directives, etc. Controllers should never instantiate service objects directly. By following this pattern, you will ensure that your application components are as testable and as simple as possible. For example, having your controller open a connection to a service endpoint or database is considered bad practice. Where are you getting your server / url from? What if we want to hit the staging server instead of production?

Resources

Conclusion

This is the first of many posts exploring AngularJS. I’ll be going through the requirements for using AngularJS to create a typical line of business application. It should be note that at the time of this writing (May 2016), Angular is going through a large conceptual shift from 1.X to 2.X. I will be focusing on concepts related to 1.X, primarily as this is what I’m using to build production applications now.