Introduction
Angular, coupled with TypeScript, offers a powerful combination for building robust and maintainable web applications.
However, to maximize its potential, it's important to be aware of certain "don'ts" of Angular development. Avoiding these pitfalls ensures clean, efficient, and bug-free code.
This blog provides a thorough explanation of what not to do in Angular development for creating great Angular applications.
Don'ts in Angular
Don't use the EventEmitter class directly:
The EventEmitter class is a powerful tool, but it can be misused. If you use the EventEmitter class directly, you will have to create a new EventEmitter instance every time the property is changed. This can lead to unnecessary object creation and memory allocation, which can impact the performance of your application, especially in scenarios where events are emitted frequently.
Instead, you should use the '@Output' decorator to create a more efficient EventEmitter instance. which prevents memory leaks by leveraging Angular's automatic subscription management, and optimizes event handling within your Angular components.
//Don't stringEmitter: EventEmitter<string>; //Do @Output() stringEmitter = new EventEmitter<string>();
Asynchronous Operations Shouldn't Block the Main Thread:
Performing long running or heavy computations synchronously on the main thread can degrade user experience and make your application unresponsive.
Employ asynchronous techniques such as web workers, or use Promises and Observables for non-blocking operations. This ensures that your application remains fluid, responsive, and user-friendly.
Not Unsubscribing from Subscriptions:
When working with observables or event subscriptions, always remember to unsubscribe when they are no longer needed. Failing to unsubscribe can lead to memory leaks and unexpected behavior, as resources remain allocated even when they're no longer in use.
Utilize the 'ngOnDestroy' lifecycle hook within Angular components to unsubscribe and release resources appropriately.
class MyComponent implements OnInit, OnDestroy { data: string; private dataSubscription: Subscription; constructor(private dataService: DataService) {} ngonInit() { this.dataSubscription = this.dataService.getData().subscribe( (data: string) = { this.data = data; }, (error: any) = { // Handle the error response here } }; } ngonDestroy() { this.dataSubscription?.unsubscribe(); } }
Don't use functions in templates:
This can lead to performance problems, as Angular will have to check the function output every time change detection is triggered.
Instead, use observables or pure pipes to bind data to the template.
@Component ({ selector: 'my-component', template: ` <!-- Template code --> <div>{{ data$ | async }}</div> `, }) class MyComponent { data$: Observable<string>; constructor (private dataService: DataService) { this.data$ = this.dataService.getDatal(); } }
Don't use 'ngOnInit()' for everything:
ngOnInit() should only be used to initialize your component's data. For other tasks, use lifecycle hooks like 'ngAfterViewInit()' or 'ngAfterContentInit()' accordingly.
Minimize Two-Way Data Binding:
Two-way data binding involves tracking changes in both the template and the component. This bidirectional synchronization can introduce additional complexity and impact performance, especially in large or complex applications.
By minimizing two-way data binding, you reduce the overhead of change detection and enhance the overall performance of your Angular application.
Don't use 'ngModel' and 'formControlName' at the same time:
The 'ngModel' directive and the 'formControlName' directive are both used to bind form controls to templates. However, using both directives at the same time is deprecated in Angular 6 and will be removed in a future version.
If you need to bind a form control to a template, you should only use the 'formControlName' directive. The 'formControlName' directive will automatically create a 'ngModel' instance for you, so there is no need to use both directives.
NOTE: If you are using 'ngModel' and 'formControlName' at the same time in your Angular application, you should update your code to use only the 'formControlName' directive. This will ensure that your application is compatible with future versions of Angular.
Don’t use inline styles in your templates:
Inline styling in Angular templates should be avoided mainly due to difficulty in managing changes and lack of reusability.
If you decide to change a particular style in the future, you'll need to locate and update every instance of that style throughout the templates. This can quickly become error-prone and time-consuming, especially in larger projects. Instead, use CSS files to style your components.
Don't Use implicit 'any' types:
While the performance impact of using 'any' types might not be immediately apparent, it can indirectly affect your application's performance in a few ways:
Dynamic Type Checking: When using "any" types, the TypeScript compiler skips static type checking for those variables. Consequently, type-related errors that could have been caught during the compilation phase are left to be discovered at runtime. This can lead to unexpected behaviors and potential performance bottlenecks.
Inefficient Runtime Operations: Without the benefit of static type checking, operations performed on variables with "any" types may require additional runtime checks and type coercion. These additional checks can introduce overhead, potentially slowing down the execution of your code.
//Don't
stringVariable!: any;
//Do
stringVariable!: string;
Here are some additional resources that you may find helpful:
Angular Style Guide: https://angular.io/guide/styleguide
New to angular? Don't worry, here is the resource for you: https://angular.io/tutorial/first-app
I hope this helps!