4 Angular Tips for Elevating Your Skills

As beginner developers, we are constantly striving to find the most effective ways to write code. In this blog post, I will share some of my personal tips and practices for doing so.

Over 6 years, while I've been focused on writing exclusively in Angular, I tried to develop some practices around it and came up with a few ideas that help me all the time, whether it's a new project or maintaining an old one.

Combining the techniques discussed in my previous article on advanced Angular components with these simple tips can help make your application more stable and efficient. While following these practices does not guarantee that your application will be free of errors, it can significantly reduce the likelihood of issues such as loops, memory leaks, and other unforeseen problems.

WRITE UNIT TESTS

The first, and most important item in this list, is to not forget to consistently write the unit tests, I've specially written the item's heading in uppercase, so as to not be ignored, trust me, once you start consistently following this practice, you will save more time than you realize.

Yes, WRITTEN TESTS = MORE TIME SAVED!

In the time when the application evolves, it's quite hard to remember what you've done earlier, so you can easily break the entire app with just a small change - tests are here to prevent this night-mare, they maintain a stable logic of your components, directives, pipes and so on - so you only focus on changes you need.

Just start writing it along with class logic, side by side, once you finished a method and you are confident there won't be changes - write the test for it.

Here's a helpful article about some good reasons why you should write tests.

Trust me, you'll thank me one day!

Don't "private" all injected services

This is a well-known technique, everyone does it, but let me ask you, do we need it to be private, or do we just need it inside the class body?

constructor(private myService: MyService) {}

If the response is the class body, I suggest you use readonly, it makes more sense for an injected service - as it can't be modified, it also becomes accessible within the class body, as we need.

constructor(readonly myService: MyService) {}

Moreover, you can also mark it private readonly, if you need it as private.

constructor(private readonly myService: MyService) {}

But let me tell you something, you already don't need private keyword, easily switch to private class features, and with the new inject function that came in Angular 14, we can rewrite the injection and make the code more readable and understandable:

@Component(...)
class MyClass {
	// In case of private.
    // You can even remove readonly,
    // it just makes more sense for me to have it
	readonly #myService = inject(MyService);
}

As you can see, I injected the same service, but in a very different way. First I use # to tell this property is private and I marked it as readonly to say it can't be modified. Easy!

Avoid code duplication

This is a typical issue of newbies, probably because not knowing there's the  concept of abstract class or an abstract class sounds hard to understand - which is vice-versa.

An abstract class allows you to write code earlier, and expand the same logic to different classes - this is especially useful to transfer the exact logic among different classes and so, avoid code duplication.

To create an abstract class, simply add abstract before class keyword:

export abstract class MyClass {}

Is important no notice, an abstract class can't be initiated, all it can do is be extended to other classes:

// First class
export class MyFirstClass extends MyClass {}
// Second class
export class MySecondClass extends MyClass {}

Now, MyFirstClass and MySecondClass have the same logic within MyClass but different instances.

In Angular though, to resolve dependency injection inside an abstract class, we must add either @Injectable() or @Directive() decorators. I usually use @Directive() but it's a matter of choice.

@Directive()
export abstract class MyClass {
	readonly #myService = inject(MyService);
}

Now, MyFirstClass and MySecondClass share the same instance of MyService.

Check out more about how to use an abstract class in Angular and feel free to take advantage of it.

Use template-driven forms

In Angular, a template-driven form is a type of form that is created and managed using template-based syntax in the HTML template of your component. This means that the form and the logic for handling the form are defined in the template, rather than in the component class.

Template-driven forms are easy to use and require less code than reactive forms. They are based on standard HTML and use familiar directives such as ngModel and ngSubmit to bind data and handle the form submissions.

One of the main advantages of template-driven forms is that they are simple to use, making them a good choice for small forms or for developers who are new to Angular.

However, it is believed they are not as flexible or powerful as reactive forms and may not be the best choice for more complex forms, but here's the trust, they're both built on top of a common Forms API.

Thanks to the very descriptive Tim Deschryver's blog post about Template-driven forms, this myth has been destroyed.

In the nutshell, template-driven forms are more than enough for complex forms, with the support of validators, form errors, dynamic forms, and testing, easier to use and require less code than reactive forms.


This is all I wanted to share with you in this blog post, if you have other tips I can include in this list, leave them in the comments below.