Controllers & $scope
Everything up to now used ng-init to fake some starting data, which is a demo-only trick — real AngularJS apps set up their data and behavior in a controller, a plain JavaScript function tied to a section of the page through ng-controller. This lesson is the one everything after it depends on.
Defining a controller
A controller is registered on a module (covered fully next lesson) and receives $scope as an argument — the object that bridges the controller's JavaScript and the template's HTML:
var app = angular.module('myApp', []); app.controller('ProfileController', function($scope) { $scope.name = 'Priya'; $scope.points = 120; $scope.addPoint = function() { $scope.points++; }; });
<div ng-app="myApp" ng-controller="ProfileController"> <p>{{ name }} has {{ points }} points.</p> <button ng-click="addPoint()">+1</button> </div>
Priya has 120 points. [+1] Clicking the button runs addPoint(), which increments $scope.points — the paragraph re-renders to "Priya has 121 points." with no manual DOM update written anywhere.
Everything the template can see — name, points, addPoint() — was put there by the controller assigning it onto $scope. Think of $scope as the one object both the JavaScript and the HTML agree to read and write through.
ng-click and other event directives
ng-click is the directive equivalent of onclick — it runs an expression (usually a function call, as above) in response to a click, without you attaching an event listener by hand.
Nested controllers and scope inheritance
An ng-controller placed inside another creates a child scope that prototypally inherits from its parent — it can read the parent's properties directly, without any special syntax:
<div ng-app="myApp" ng-controller="OuterController"> <p>Outer sees: {{ company }}</p> <div ng-controller="InnerController"> <p>Inner sees: {{ company }}</p> </div> </div>
Outer sees: Acme Co Inner sees: Acme Co
Even though InnerController never sets company itself, it can read the value OuterController put on its scope — child scopes fall back to the parent's properties automatically, exactly like prototypal inheritance for plain JavaScript objects.
InnerController does $scope.company = 'New Name', it creates a brand-new property on the child scope that shadows the parent's — the outer scope's value never changes, and now the two scopes disagree. The standard fix is binding to a property on an object ($scope.data.company) rather than a bare primitive ($scope.company), since object properties are looked up by reference and don't get shadowed the same way. AngularJS developers call this "the dot rule": if a binding in your template doesn't have at least one dot in it, assignment from a child scope is likely to misbehave.