Keep Moving Forward | X-Team Magazine

Nested Controllers, ngInclude, and $scope

Written by Andre Drougge | Oct 31, 2014 4:00:00 AM

When working with AngularJS, $scope will have a pivotal role in your work and when starting out, you might run into road bumps unless you have a rough idea of how to work with it. I’ll aim to explain a couple issues about $scope and ngInclude that I’ve run into.

Below you’ll learn how to avoid targeting $parent or $child scopes when using ng-include, and how to debug your code when realizing that $watchers aren’t operating on the correct model or scope.

$scope ID

First, you need to understand this: Each controller has its own scope, and each scope has a unique ID. Listeners/watchers will apply only to the models in the scope where they were applied.

For instance, a watcher in controller AppCtrl.js who listens to $scope.my_model, will only listen to that model in that scope, not on my_model in a scope with a different ID.

You can find the scope ID in $scope.$id.

console.log($scope.$id);

Nested controllers $scope ID

When working with nested controllers, such as the example below..

index.html

<div ng-controller="AppCtrl">
  <div ng-controller="LoginCtrl">
    // Login code..
  </div>
  <div ng-controller="TableCtrl">
    // Table codes...
  </div>
</div>

.. the $scope.$id of AppCtrl, will be 001, but for LoginCtrl it may be 002.

If by chance you need to apply a change to a model on the AppCtrl‘s scope, from the LoginCtrl, you can do so by targeting its parent scope $scope.$parent, though if you find yourself targeting different scope than your controllers’ natural scope, it’s probable you should move your functionality to its appropriate controller instead.

ngInclude and $scope.$id

Here’s something that threw me off, ngInclude creates a new scope!

You’ll need to keep that in mind when using ngInclude to split your templates into partials. Instead of applying a controller to an element in a layout-template, apply the controller to an element in the partial. That way you’ll not need to target its parent’s scopes, coupling controllers together by scope. Here’s an example:

layout.html

<div ng-controller="LoginCtrl">
    <div ng-include="login.html"></div>
</div>

login.html

<form-field ng-field-data=""></form-field>
<form-field ng-field-data=""></form-field>

In the case above, you would want to handle the login model in the LoginCtrl controller, but the scope of the login partial login.html will be one step deeper. Instead, define the controller on the same level as the partial (see below).

layout.html

<div ng-include="login.html"></div>

login.html

<div ng-controller="LoginCtrl">
    <form-field ng-field-data=""></form-field>
    <form-field ng-field-data=""></form-field>
</div>

$scope is an important part of AngularJS and the more understanding you have about it, the better and more testable code you will write. To get more in-depth information, here are a few links that explain this further. Thanks for checking in!