![]()
When migrating an AngularJS application to Angular, one major challenge is converting AngularJS directives into Angular components. Since Angular components are a modern replacement for directives, understanding this transition is crucial.
1. Key Differences: AngularJS Directives vs. Angular Components
| Feature | AngularJS Directives | Angular Components |
|---|---|---|
| Definition | directive() function | @Component decorator |
| Structure | Complex and flexible | Simpler and component-based |
| Templates | Defined using template or templateUrl | Uses inline HTML or templateUrl |
| Scope | $scope (isolated or inherited) | Uses class properties (this) |
| Bindings | @, =, & for attribute bindings | Uses @Input() and @Output() |
| Controllers | Defined inside directive (controller) | Uses a class-based approach |
2. Step-by-Step Conversion
Let’s go step by step and convert an AngularJS directive into an Angular component.
Step 1: AngularJS Directive (Old Code)
Consider an AngularJS directive that displays user details.
AngularJS Directive (user-card.directive.js)
angular.module('myApp')
.directive('userCard', function() {
return {
restrict: 'E',
scope: {
user: '='
},
template: `
<div class="user-card">
<h3>{{ user.name }}</h3>
<p>Email: {{ user.email }}</p>
</div>
`,
controller: function($scope) {
console.log('User:', $scope.user);
}
};
});
Uses restrict: 'E' (Element directive).
Defines an isolated scope (user: '=').
Uses a controller inside the directive.
Step 2: Convert to an Angular Component
Angular Component (user-card.component.ts)
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-user-card',
template: `
<div class="user-card">
<h3>{{ user.name }}</h3>
<p>Email: {{ user.email }}</p>
</div>
`,
styleUrls: ['./user-card.component.css']
})
export class UserCardComponent {
@Input() user: { name: string; email: string };
constructor() {
console.log('User:', this.user);
}
}
Uses @Component decorator instead of directive().
Replaces AngularJS $scope with a class property @Input() user.
Uses TypeScript and a class-based approach.
Step 3: Using the Angular Component in an Angular Template
AngularJS Usage (Old)
<user-card user="currentUser"></user-card>
Angular Usage (New)
<app-user-card [user]="currentUser"></app-user-card>
Uses property binding ([user]) instead of AngularJS user="currentUser".
3. Handling Transclusion (ng-transclude)
In AngularJS, transclusion (ng-transclude) allows injecting content inside directives.
AngularJS Directive with Transclusion
angular.module('myApp')
.directive('card', function() {
return {
restrict: 'E',
transclude: true,
template: `
<div class="card">
<h2>Card Title</h2>
<div ng-transclude></div>
</div>
`
};
});
Angular Equivalent Using ng-content
import { Component } from '@angular/core';
@Component({
selector: 'app-card',
template: `
<div class="card">
<h2>Card Title</h2>
<ng-content></ng-content>
</div>
`,
styleUrls: ['./card.component.css']
})
export class CardComponent {}
Uses <ng-content></ng-content> instead of ng-transclude.
4. Handling Two-Way Binding (= in AngularJS)
In AngularJS, two-way binding is done using =.
scope: {
user: '='
}
In Angular, use @Input() for input binding and @Output() with EventEmitter for two-way binding.
Angular Component with Two-Way Binding
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-user-input',
template: `
<input [(ngModel)]="userName" (ngModelChange)="onUserNameChange()" />
`
})
export class UserInputComponent {
@Input() userName: string;
@Output() userNameChange = new EventEmitter<string>();
onUserNameChange() {
this.userNameChange.emit(this.userName);
}
}
Uses @Output() and EventEmitter for two-way binding.
5. Handling Event Binding (& in AngularJS)
In AngularJS, & is used for passing functions.
scope: {
onClick: '&'
}
In Angular, use @Output() and EventEmitter.
AngularJS Directive
<button ng-click="onClick()">Click Me</button>
Angular Component
@Component({
selector: 'app-click-button',
template: `<button (click)="handleClick()">Click Me</button>`
})
export class ClickButtonComponent {
@Output() onClick = new EventEmitter<void>();
handleClick() {
this.onClick.emit();
}
}
Uses EventEmitter instead of &.
