In AngularJS, $scope
acts as a bridge between the controller and the view. However, excessive use of $scope
can lead to pollution, making the application harder to maintain and debug. In this guide, we’ll explore best practices to avoid $scope
pollution while keeping our controllers clean and efficient.
1. Use Controller As
Syntax Instead of $scope
Best Practice:
Instead of using $scope
, use Controller As syntax and bind variables to this
.
Example (Bad Approach – $scope
Pollution)
app.controller('UserController', function($scope) {
$scope.username = "John Doe";
$scope.age = 30;
});
<div ng-controller="UserController">
<h1>{{ username }}</h1>
<p>Age: {{ age }}</p>
</div>
Example (Best Approach – Using Controller As
)
app.controller('UserController', function() {
var vm = this; // Using 'vm' instead of $scope
vm.username = "John Doe";
vm.age = 30;
});
<div ng-controller="UserController as user">
<h1>{{ user.username }}</h1>
<p>Age: {{ user.age }}</p>
</div>
Why?
- Prevents global
$scope
pollution. - Improves readability and maintainability.
- Aligns with best practices from Angular 2+.
2. Use Services for Shared Data
Best Practice:
Instead of storing data in $scope
, move it to a service.
Example (Bad Approach – Using $scope
for Shared Data)
app.controller('Ctrl1', function($scope, $rootScope) {
$rootScope.sharedData = "Hello";
});
app.controller('Ctrl2', function($scope, $rootScope) {
console.log($rootScope.sharedData);
});
Example (Best Approach – Using a Service Instead)
app.service('SharedService', function() {
this.data = "Hello";
});
app.controller('Ctrl1', function(SharedService) {
var vm = this;
vm.sharedData = SharedService.data;
});
app.controller('Ctrl2', function(SharedService) {
var vm = this;
vm.sharedData = SharedService.data;
});
Why?
- Avoids polluting
$rootScope
. - Encapsulates data properly for better reusability.
3. Avoid Using $scope.$watch()
for Data Binding
Best Practice:
Use ng-model or one-time binding (::
) instead of $scope.$watch()
.
Example (Bad Approach – Using $watch
)
app.controller('WatchController', function($scope) {
$scope.username = "John Doe";
$scope.$watch('username', function(newValue, oldValue) {
console.log("Username changed:", newValue);
});
});
Example (Best Approach – Using ng-model
)
app.controller('UserController', function() {
var vm = this;
vm.username = "John Doe";
});
htmlCopyEdit<input type="text" ng-model="user.username">
Why?
$watch
adds performance overhead.ng-model
automatically syncs with the model.
4. Use One-Time Binding (::
) When Data Won’t Change
Best Practice:
Use ::
for static data to prevent unnecessary re-evaluations.
Example (Bad Approach – Data Re-evaluates on Every Digest Cycle)
<h1>{{ user.name }}</h1>
Example (Best Approach – Using One-Time Binding)
<h1>{{ ::user.name }}</h1>
Why?
- Reduces unnecessary digest cycles.
- Improves performance for static data.
5. Remove Event Listeners to Avoid Memory Leaks
Best Practice:
Always clean up $scope.$on()
listeners.
Example (Bad Approach – Memory Leak Risk)
app.controller('EventController', function($scope) {
$scope.$on('customEvent', function(event, data) {
console.log("Received:", data);
});
});
Example (Best Approach – Remove Listener on $destroy
)
app.controller('EventController', function($scope) {
var unbind = $scope.$on('customEvent', function(event, data) {
console.log("Received:", data);
});
$scope.$on('$destroy', unbind); // Clean up event listener
});
Why?
- Prevents memory leaks.
- Ensures event listeners are removed when controllers are destroyed.
6. Avoid Using $rootScope
for Global Data
Best Practice:
Use services or constants instead.
Example (Bad Approach – Using $rootScope
)
app.run(function($rootScope) {
$rootScope.globalMessage = "Hello World!";
});
<h1>{{ globalMessage }}</h1>
Example (Best Approach – Using a Constant)
app.constant('APP_MESSAGE', 'Hello World!');
app.controller('MainController', function(APP_MESSAGE) {
var vm = this;
vm.message = APP_MESSAGE;
});
<h1>{{ main.message }}</h1>
Why?
$rootScope
leads to global scope pollution.- Constants provide better modularity.
7. Limit the Use of $scope.$apply()
and $scope.$digest()
Best Practice:
Use Angular services (like $timeout
and $http
) instead.
Example (Bad Approach – Using $apply
Unnecessarily)
setTimeout(function() {
$scope.message = "Updated!";
$scope.$apply(); // Avoid this if possible
}, 1000);
Example (Best Approach – Use $timeout
)
app.controller('TimeoutController', function($timeout) {
var vm = this;
$timeout(function() {
vm.message = "Updated!";
}, 1000);
});
Why?
$apply()
forces a digest cycle, which may impact performance.$timeout
ensures safe digest handling.