$scope - A glue between javascript code (controllers) and HTML (view)
Picture from Modular Design of AngularJS Application
A scope is an object that glues the View with Controller. It holds the Model data that we pass to the View.
Scope uses Angular's two-way data binding to bind model data to view.
In other words, a $scope is an object that links Controller to the View.
It is the Controller that initializes the data that the View needs, and this is done by making changes to the $scope.
Again, the $scope is an object that contains all the data to which HTML is bound. So, the scope becomes the Model.
$scope is the glue our javascript (controllers) and the HTML (view). Everything attached to the $scope is automatically $watched by AngularJS and updated.
Let's look into the following sample which uses all those three component: $scope, controller, and HTML. It plays with names of Galaxy, we can add and remove the names on the fly:
<html> <head> <title>Hello scope and controller A</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.18/angular.min.js"></script> </head> <body> <div ng-app="mainApp" ng-controller="nameController"> Name: <input type="text" ng-model="newName"/> <button ng-click="add()">Add</button> <button ng-click="remove()">Remove</button> <h2>Galaxies</h2> <ul> <li ng-repeat="name in names"> {{name}} </li> </ul> </div> <script> var app = angular.module("mainApp", []); app.controller("nameController", function($scope) { $scope.names = ["Centaurus A", "Andromeda Galaxy", "Milky Way"]; $scope.add = function() { $scope.names.push($scope.newName); $scope.newName = ""; }; $scope.remove = function(name) { var n = $scope.names.indexOf(name); $scope.names.splice(n,1); }; }); </script> </body> </html>
Let's play with the names!
Click the "Add" or "Remove" button to add or remove a name.
The code is using 4 scope variables which are passed in when the controller function nameController() takes $scope as its parameter:
- $scope.name
- $scope.names
- $scope.add
- $scope.newName
When adding properties to the $scope object in the controller, the view (HTML) gets access to these properties.
The scope is a JavaScript object with properties and methods, which are available for both the view and the controller.
In the view, we do NOT use the prefix $scope, we just refer to a propertyname, like {{name}}.
Note also that it's the controller that initializes the variables.
Here is a slightly modified version:
<html> <head> <title>Hello scope and controller B</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.18/angular.min.js"></script> </head> <body> <div ng-app="mainApp" ng-controller="nameController"> <form ng-submit="add()"> Name: <input type="text" ng-model="newName"/> <input type="submit" value="Add"/> </form> <h2>Galaxies</h2> <ul> <li ng-repeat="name in names"> {{name}} <a href="" ng-click="remove(name)"> Remove</a> </li> </ul> </div> <script> var app = angular.module("mainApp", []); app.controller("nameController", function($scope) { $scope.names = ["Centaurus A", "Andromeda Galaxy", "Milky Way"]; $scope.add = function() { $scope.names.push($scope.newName); $scope.newName = ""; }; $scope.remove = function(name) { var n = $scope.names.indexOf(name); $scope.names.splice(n,1); }; }); </script> </body> </html>
This time, we did not use the "Remove" button, but instead we moved the remove link right next to each name. Also, note that we replaced ng-click with ng-submit for the add().
Here is another variation of the previous one:
<html> <head> <title>Hello scope and controller C</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script> </head> <body> <div ng-app="mainApp" ng-controller="nameController"> <!-- input and button it add a new name --> <div> <input type="text" ng-model="input"> <button type="submit" ng-click="add()">Add</button> </div> <!-- list of names with a button to remove that name --> <h2>Galaxies</h2> <ul> <li ng-repeat="name in names"> {{name}} <button ng-click="remove($index)">Remove</button> </li> </ul> </div> <script> var app = angular.module("mainApp", []); app.controller('nameController', function($scope) { // initial names $scope.names = ["Centaurus A", "Andromeda Galaxy", "Milky Way"]; // add a name $scope.add = function() { $scope.names.push($scope.input); }; // remove a name $scope.remove = function(index) { $scope.names.splice(index, 1); }; }); </script> </body> </html>
- Added "Remove" buttons instead of links.
- The way we're handling the list.
In the examples above, we have only one scope, so knowing our scope is not an issue. However, for larger applications, there can be some sections in the HTML DOM which can only access certain scopes.
At any time during our code development process, we should know which scope we are dealing with.
The following example has two scopes: controller's and root's
<!DOCTYPE html> <html> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script> <body ng-app="myApp"> <p>The rootScope's favorite musician: <b>{{musician}}</b></p> <div ng-controller="myCtrl"> <p>The scope of the controller's favorite musician: <b>{{musician}}</b></p> </div> <p>The rootScope's favorite musician is still: <b>{{musician}}</b></p> <script> var app = angular.module('myApp', []); app.run(function($rootScope) { $rootScope.musician = 'Katy Perry'; }); app.controller('myCtrl', function($scope) { $scope.musician = "Taylor Swift"; }); </script> <p>Controller does not overwrite the rootScope's musician!</p> </body> </html>
Every application has a $Scope which is the scope created on the HTML element that contains the ng-app directive.
The rootScope is available in the entire application.
If a variable bears the same name in both the current scope and in the rootScope, the application use the one in the current scope.
This example is to demonstrate the internal workings of Angular, especially, how does it know any data for view has been updated. To investigate the process, we're going to change scope values asynchronously (step out of Angular) so that updates don't propagate without .apply(). Actually, we get the test results from https://github.com/curran/screencasts/blob/gh-pages/introToAngular/examples/snapshots/snapshot12/index.html.
<html ng-app="nameApp"> <head> <meta charset="utf-8"> <title>Angular.js Example</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script> <script> var nameApp = angular.module('nameApp', []); nameApp.controller('nameController', function ($scope){ $scope.firstName = 'Claude'; $scope.$watch('lastName', function(newValue, oldValue){ console.log('new value is ' + newValue); }); setTimeout(function(){ $scope.lastName = 'Debussy'; // without this apply(), the lastName won'b be updated //$scope.$apply(); }, 1000); }); </script> </head> <body ng-controller="nameController"> First name:<input ng-model="firstName" type="text"/> <br /> Last name:<input ng-model="lastName" type="text"/> <br /><br /> Hello {{firstName}} {{lastName}}! </body> </html>
If we uncomment the following line, it will properly update the lastName.
$scope.$apply();
It turns out that AngularJS internally fires up $scope.$apply() when we do:
<li ng-repeat="name in names"> {{ name }} </li>
in the previous section's example.
- Introduction
- Directives I - ng-app, ng-model, and ng-bind
- Directives II - ng-show, ng-hide, and ng-disabled
- Directives III - ng-click with toggle()
- Expressions - numbers, strings, and arrays
- Binding - ng-app, ng-model, and ng-bind
- Controllers - global controllers, controller method, and external controllers
- Data Binding and Controllers (Todo App)
- Todo App with Node
- $scope - A glue between javascript (controllers) and HTML (the view)
- Tables and css
- Dependency Injection - http:fetch json & minification
- Filters - lower/uppercase, currenty, orderBy, and filter:query with http.get()
- $http - XMLHttpRequest and json file
- Module - module file and controller file
- Forms
- Routes I - introduction
- Routes II - separate url template files
- Routes III - extracting and using parameters from routes
- Routes IV - navigation between views using links
- Routes V - details page
- AngularJS template using ng-view directive : multiple views
- Nested and multi-views using UI-router, ngRoute vs UI-router
- Creating a new service using factory
- Querying into a service using find()
- angular-seed - the seed for AngularJS apps
- Token (JSON Web Token - JWT) based auth backend with NodeJS
- Token (JSON Web Token - JWT) based auth frontend with AngularJS
- Twitter Bootstrap
- Online resources - List of samples using AngularJS (Already launched sites and projects)
- Meteor Angular App with MongoDB (Part I)
- Meteor Angular App with MongoDB (Part II - Angular talks with MongoDB)
- Meteor Angular App with MongoDB (Part III - Facebook / Twitter / Google logins)
- AngularJS Tutorial: Shopping cart sample
- Laravel 5 / Angular Auth using JSON Web Token (JWT) - Prod
- Scala/Java Play app with Angular
AngularJS
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization