> ## Content Index
> Fetch the complete content index at: https://www.jonathancreamer.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# The state of angularjs controllers
- URL: https://www.jonathancreamer.com/the-state-of-angularjs-controllers/
- Published: 2014-05-06T16:36:42.000Z
- Updated: 2014-05-06T16:38:17.000Z
- Author: Jonathan Creamer
- Tags: javascript, angularjs, mvc, services, factories, controllers

Angular.js is based on the ever popular MVC architecture pattern. However, like many other JavaScript frameworks, MVC can very easily be muddied up and misused.

Understanding the framework you're using, whether that be Angular, Backbone, etc, and how the different M-V-? pieces work together is important to the maintainability and scalability of your application. When the ideas of these different MV? architectures get misconstrued, bad things can happen.

For example in Angular, you'll see many examples of controllers holding model state that in reality they probably should not be.

> The third part, the controller, accepts input and converts it to commands for the model or view.  
> \-- Wikipedia (1)

The controller's job is not to be the model, the controller's job is to talk to the "model".

For example, take an order controller...

```prettyprint
angular.module('Store', [])
.controller('OrderCtrl', function(Products) {
    this.products = Products.query();
    
    this.items = [];
    
    this.addToOrder = function(item) {
        this.items.push(item);
    };
    
    this.removeFromOrder = function(item) {
        this.items.splice(this.items.indexOf(item), 1);
    };
    
    this.totalPrice = function() {
        return this.items.reduce(function(memo, item) {
            return memo + (item.qty * item.price);
        }, 0);
    };
});

```

What you have here is a controller that has a list of `products` retrieved from the `Products` service. Then there is a list of `items` that is on the `OrderCtrl`. At first glance, this is not unlike much of the code you'll see in Angular's docs [https://docs.angularjs.org/api/ng/directive/ngController](https://docs.angularjs.org/api/ng/directive/ngController?ref=jonathancreamer.com).

For a "small prototype", maybe that's fine. For larger apps however, probably not a great idea. What if you need to have a cart controller that displays the total items in your order, or the price? What if you want to have a separate order controller in some other widget?

You'll either end up duplicating code, or having to hack some way for the controllers to talk to each other to keep their state up to date.

The solution to this problem is to do utilize the "M" of MVC properly and move that state out of your controller into some "model".

With angular, there's a little bit of ambiguity in what the "M" really is. I like to think of the "model" as the actual data you retrieve from the backend, and how you retrieve it on the client. With angular the ambiguity in the "model" is made difficult in part because there are lots of different ways to create a "model" aka services, factories, and providers. That's why there are so many [questions](http://stackoverflow.com/questions/15666048/angular-js-service-vs-provider-vs-factory?ref=jonathancreamer.com) on stack overflow about it.

One of the easiest ways to deal with it is to use `angular.factory` as a "model".

```prettyprint
angular.module('Store')
.factory('Order', function() {    
    var add = function(item) {
        this.items.push(item);
    };
    
    var remove = function(item) {
        if (this.items.indexOf(item) > -1) {
          this.items.splice(this.items.indexOf(item), 1);  
        }
    };
    
    var total = function() {
        return this.items.reduce(function(memo, item) {
            return memo + (item.qty * item.price);
        }, 0);
    };

    return {
    	items: [],
        addToOrder: add,
        removeFromOrder: remove,
        totalPrice: total
    };
});

```

You now have an injectable "model" you can span across multiple controllers, and remove the state from the controller.

```prettyprint
angular.module('Store', [])
.controller('OrderCtrl', function(Products, Order) {
    this.products = Products.query();
    this.items = Order.items;
    
    this.addToOrder = function(item) {
		Order.addToOrder(item);
    };
    
    this.removeFromOrder = function(item) {
        Order.removeFromOrder(item);
    };
    
    this.totalPrice = function() {
    	return Order.total();
    };
});

```

The controller is now much thinner, and holds no state. This is important because controllers are created and destroyed very often in the lifecycle of an angular app, whereas a `factory` is only created a single time.

Now you can use the `Order` "model" in other controllers quite easily.

```prettyprint
angular.module('Store', [])
.controller('CartCtrl', function($scope, Order) {
    $scope.items = Order.items;
  
    $scope.$watchCollection('items', function() {
      $scope.totalPrice = Order.totalPrice().toFixed(2);
    });
});

```

The `$scope.$watchCollection` can keep an eye out for changes on the `Order.items` array and update the `$scope.totalPrice` when the items change.

There are other ways of doing this such as firing an event when a new item is added to the `Order`, but this should work in this case. The main benefit here is that the order has been pulled out into it's own "model" that can more easily be reused in other parts of the application.

Here's a JSBin of the code above...

[JS Bin](http://jsbin.com/rifob/1/embed?js,output&ref=jonathancreamer.com)

1. [http://en.wikipedia.org/wiki/Model–view–controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller?ref=jonathancreamer.com)