Biggest Angular Pitfalls and how to avoid them — Part One — Circular Dependency

Indraneel Pole
CodeX
Published in
3 min readJun 14, 2022

So another Angular pitfall post. I know there are millions of them already on Internet. And I still decide to write one more. Why is that, you might wonder? Well, for the simple reason, because even after coding in Angular Framework extensively for last five years, I still sometimes fall victim to these pitfalls. So this post is also for documenting these pitfalls for myself as well as for those who might google a problem and land here accidently :)

I am gonna do this topic in parts, because I just don’t want to write another listical. Instead, I want to dive deeper into each one of the pitfalls. So, in the first part, we are going to look at the favorite mistake of every Angular developer — Circular Dependency.

Circular Dependency is the most common mistake a newbie Angular developer can make. It is not even something specific to Angular Framework honestly. It is more of a Dependency Injection problem.

So, what is circular dependency? Imagine you have two services, lets call them pizza.service.ts and delivery.service.ts. In the pizza.service we are injecting delivery.service because well imagine, we need the delivery status in our pizza.service. That is fine AS LONG AS, we don’t need pizza.service itself in delivery.service. If at the same time we also inject the pizza.service in delivery.service, we have circular dependency on our hand.

How to solve this you might ask? Well, in such cases, it is best to put the dependent code (For example status variable in delivery.service) in a third service which doesn’t depend on any of the two above mentioned services. And then, just inject this third service in these two.

Sometimes however, the issue is more complex than this. For instance, if you have lazy loading enabled in your Angular application. Now, in this lazy loaded application, you have two different modules. Module A has component — pizza.component, pasta.component, and tiramisu.component. On the other hand, Module B has delivery.component, payment.component, and extras.component, and some services.. Now on surface we have divided the components cleanly between modules. But in practicality, we need some component from Module A in component of Module B, AND some service of Module B in a component of Module A. Now, in this example it is identifiable pretty easily, but in complex applications, that might not be the case.

The problem

In such cases, the cleanest way always is to implement a shared.module that keeps common components, and then import shared.module in both the modules.

The solution

Be careful though — This is more of an architecture problem than an Angular problem. Always ask yourself, does it make sense to put a certain component in a certain modules. What is the business usecase? What is the clearner workflow? Don’t just blindly put everything in shared.module. If you have unnecessary things stored in shared.module, it might defeat the purpose of having lazy loading at all. You can also have smaller cleaner multiple shared modules in case you have multiple things that needs to be shared between lazy modules. In that case, just reference the shared module you need.

Smaller shared modules

Circular dependencies can be rabbit hole. More so, when you have a huge monolith. While I understand the drawbacks of writing a monolith Frontend in today’s day and age, it is sometimes unavoidable considering the project life cycle. In such cases, it is always better to design the application from start to avoid such pitfalls in future. Circumnavigating a possible future problem, can seem expensive in short term, but in long term it is always cost effective than refactoring.

In next part, we will talk about common mistakes with Subscriptions and how to avoid them.

Until then :)

--

--

Indraneel Pole
CodeX
Writer for

Full-stack software Engineer at daenet GmbH, Lecturer at Frankfurt University of Applied Sciences, ML, AI, Web, Mobile - Software Engineering in general