Replacing $scope with Angular component-based architecture

Loading

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 $scope is no longer used in Angular
  • How to replace $scope with Angular component-based architecture
  • Step-by-step migration from $scope to Angular components
  • Best practices

1. Why $scope is Removed in Angular 2+?

Feature$scope (AngularJS)Component-Based (Angular 2+)
Data Binding$scope and $watchComponent Properties & @Input()
Communication$broadcast, $emit, $on@Input(), @Output(), and Services
Dependency Injection$scope and $injectorConstructor Injection
PerformanceTwo-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.messagemessage 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.

Leave a Reply

Your email address will not be published. Required fields are marked *