![]()
AngularJS (1.x) used $scope for data binding and controller-based architecture. However, modern Angular (2+) follows a component-based architecture, which eliminates $scope and introduces @Component decorators, @Input(), @Output(), Services, and Observables.
This guide will cover:
- Why
$scopeis no longer used in Angular - How to replace
$scopewith Angular component-based architecture - Step-by-step migration from
$scopeto Angular components - Best practices
1. Why $scope is Removed in Angular 2+?
| Feature | $scope (AngularJS) | Component-Based (Angular 2+) |
|---|---|---|
| Data Binding | $scope and $watch | Component Properties & @Input() |
| Communication | $broadcast, $emit, $on | @Input(), @Output(), and Services |
| Dependency Injection | $scope and $injector | Constructor Injection |
| Performance | Two-way binding ($digest) | Unidirectional Data Flow |
Modern Angular provides better performance, modularization, and code maintainability compared to the $scope-based approach.
2. Step-by-Step Migration from $scope to Angular Components
Step 1: Remove $scope in Controllers
AngularJS controllers used $scope to manage data and events.
Old AngularJS (app.js)
angular.module('myApp', [])
.controller('MainController', function($scope) {
$scope.message = "Hello, AngularJS!";
$scope.updateMessage = function() {
$scope.message = "Updated Message!";
};
});
Old AngularJS HTML (index.html)
<div ng-controller="MainController">
<p>{{ message }}</p>
<button ng-click="updateMessage()">Update</button>
</div>
Step 2: Convert Controller to an Angular Component
In Angular 2+, instead of controllers, we create components using @Component().
New Angular Component (app.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
message: string = "Hello, Angular!";
updateMessage(): void {
this.message = "Updated Message!";
}
}
New Angular Template (app.component.html)
<p>{{ message }}</p>
<button (click)="updateMessage()">Update</button>
Changes:
$scope.message → message property in the component
$scope.updateMessage() → updateMessage() method in the component
ng-click → (click) event binding
Step 3: Replace $scope with Component Inputs & Outputs
In AngularJS, we often use $scope for passing data between controllers and directives. In Angular, we use @Input() and @Output() for communication between components.
Old AngularJS Child Component (childComponent.js)
angular.module('myApp').directive('childComponent', function() {
return {
scope: { name: '=' },
template: '<p>Child: {{ name }}</p>'
};
});
New Angular Child Component (child.component.ts)
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: '<p>Child: {{ name }}</p>'
})
export class ChildComponent {
@Input() name!: string;
}
Using Child Component in Parent (parent.component.html)
<app-child [name]="'John Doe'"></app-child>
$scope data binding is replaced with @Input().
Step 4: Replace $scope Events with @Output()
Old AngularJS Event Communication (app.js)
angular.module('myApp', [])
.controller('ParentController', function($scope) {
$scope.parentMessage = "Hello from Parent!";
$scope.updateMessage = function(newMessage) {
$scope.parentMessage = newMessage;
};
})
.directive('childComponent', function() {
return {
scope: { updateMessage: '&' },
template: '<button ng-click="updateMessage({newMessage: \'Updated from Child!\'})">Click Me</button>'
};
});
New Angular Using @Output() (child.component.ts)
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-child',
template: '<button (click)="sendMessage()">Click Me</button>'
})
export class ChildComponent {
@Output() messageEvent = new EventEmitter<string>();
sendMessage(): void {
this.messageEvent.emit('Updated from Child!');
}
}
New Angular Parent Component (parent.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class ParentComponent {
parentMessage: string = "Hello from Parent!";
updateMessage(newMessage: string): void {
this.parentMessage = newMessage;
}
}
New Angular Parent HTML (parent.component.html)
<p>{{ parentMessage }}</p>
<app-child (messageEvent)="updateMessage($event)"></app-child>
$scope.updateMessage is replaced with @Output() and EventEmitter.
Step 5: Replace $scope with Services for Data Sharing
In AngularJS, we use $scope for sharing data. In Angular, Services provide a better approach.
Old AngularJS Service (app.js)
angular.module('myApp').service('DataService', function() {
this.message = "Hello, Service!";
});
New Angular Service (data.service.ts)
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class DataService {
message: string = "Hello, Service!";
}
Using Service in Component (app.component.ts)
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-root',
template: '<p>{{ dataService.message }}</p>'
})
export class AppComponent {
constructor(public dataService: DataService) {}
}
$scope is replaced with Services for better state management.
