The Hardest Parts of Learning Angular
By: Lewis Fairweather
Tags: Technology, JavaScript, Angular, Software Engineering, Programming

“Angular is beginner friendly” — Not a single person

A Complete JavaScript Web Framework

What makes Angular different?

Angular is one of the most popular JavaScript frameworks. Developed and maintained by Google, it is used to build modern Single-Page Application’s (SPA’s), and Progressive Web Application’s (PWA’s).

As a complete framework, it has everything you need for a JavaScript web application.

It provides opinionated architecture enabling full separation of concerns by dividing application structure between components, services, directives, pipes & modules. These are different types of class that provides unique characteristics and functionality. This architecture enables development that scales & works well in a large team.

It provides the full MVC of web development. It provides built-in components and templates that enable advanced dynamic rendering, in addition to modules with the capability to use lazy loading to split bundle size & reduce the upfront main bundle size.

As a web developer, using Angular you inherit solutions to the most common problems faced. These solutions are built into the framework. This is what sets it apart from React and other ‘view-focused’ libraries.

The most important and valuable features that Angular provides out-of-the-box are the Angular CLI, intelligent IDE tooling, dynamic rendering, templates, dependency injection, AOT-JIT, routing, animations, Universal Server-Side Rendering (SSR), testing, accessibility, internationalization, security functionality, PWA support, Web-Workers, and much more.

These built-in features and tools demonstrate and encourage the Angular way to do things. These are all things that you’ll have to learn to take full advantage of the framework.

TypeScript adds complexity

Angular’s conceptual approach to web development is achieved through high-level abstractions over common useful JavaScript patterns. For the web developer using Angular, this involves learning the syntactic sugar that results from these abstractions.

For those who aren’t familiar with TypeScript, or those who haven’t yet learned it, TypeScript contributes massively to the steep learning curve.

The combination of Angular and TypeScript makes it feel as though it is its’ own programming language sometimes.

It uses experimental decorators to provide annotation for its NgModules and class types as part of its architecture. In Angular, decorators are what give classes its’ purpose within the application. Every supported class type in Angular is decorated with its’ name (e.g. @Component ).

It requires a shift in mindset

As a novice Angular developer, you find that you have to alter your programming mindset. This takes time and a frustrating process. It dramatically decreases your development productivity.

This is due to a combination of…

The reactive approach (RxJS)

Unique Architecture (NgModules)

Angular classes (decorators) with single responsibilities

The idea is that when you become familiar with the framework, you finally receive your return on investment (ROI).

The Angular ROI comes in the form of rapid app development due to the scaffolding capabilities of the Angular CLI.

Until you’re comfortable with the architecture, and automatically know when you should use a Directive vs Component vs Service vs Pipe , nothing is likely to be rapid.

Once you’ve made it over the learning cliff, you feel like you can actually estimate development time again (as well as you could usually anyway). You become less likely to be tripped up by what Angular does ‘under the hood’.

But until then, you’ve got to experience the hardest parts of learning Angular.

But what are the hardest parts of learning Angular?

1) Opinionated Architecture & Unique Syntax

The Angular-specific abstractions provide syntactic sugar that enables higher-level interaction and functionality. This is seen in the way you’d define modules and components using a TypeScript decorator.

This means that the developer is spared the complexities, leaving the details “under the hood”.

Angular heavily influences the way you structure your project. Getting the most that Angular can offer means learning the difference between modules, components, directives, services, pipes, etc. These are the essential parts of an Angular application. A decorator is used above the class to indicate whether it is a @Component or a @Directive for example.

Components & Directives

Components are the building blocks of an Angular application. An application is mainly made up of lots of components. You write the UI through the components’ template which interacts with the business logic through the TypeScript class.

Angular provides component interfaces that enable certain functionality through implementing the function. These can come in the form of lifecycle hooks, such as NgOnInit using the TypeScript interface implementation implements .

For me, the hardest thing to wrap my head around was how it all relates and combines to form a web application.

The time to use a Component vs Service was easy to determine, choosing between a Component vs Directive was a little more difficult at first, but knowing the right situation to create a directive was hard.

I often found myself adding complexity to a component when I should have been designating that functionality to a directive.

Furthermore, directives can either be structural or attribute directives.

The way that you’d interact with the application from directives is the hardest thing to learn when using directives for the first time. Angular has unique ways to access the DOM and the Host through more specific syntax and TypeScript decorators such as @HostBinding and @HostListener .

Directives in Angular are a unique way to think about the DOM and take some getting used to.

Interfaces

The interfaces that Angular provides are relatively straight-forward to use, but there are hundreds. The difficulty is knowing which interface to implement in certain situations. Gaining awareness of the interfaces available and associating interfaces with certain functionality is usually accumulated through time spent on stack overflow or looking through others code.

Understanding the right circumstance to use a particular interface is near impossible to infer from the documentation as a beginner.

Modules

In Angular, modules are @NgModule ‘s. There are variations of modules such as domain feature modules, routed feature modules, routing modules, service feature modules, widget feature modules. Learning the difference is tricky because there is bound to be overlap, especially if you are rapidly developing your application, or don’t have the luxury of countless developers to share the workload.

If you’re not careful in organising modules based on their type, you’ll end up creating complex hybrid modules that do nearly everything.

The Angular documentation reference these module types:

Domain feature modules.

Routed feature modules.

Routing modules.

Service feature modules.

Widget feature modules.

Knowing the difference between these types and how they should look will improve readability and understanding of an application by other developers. It also helps it comes to refactoring and trimming your applications. It saves time knowing where to look first when you want to refactor parts of an application.

Services & Dependency Injection

Services, on the other hand, are pretty easy to understand. They should contain the ‘business logic’.

A new service is created for each specific purpose. This means they should strongly adhere to the Single Responsibility Principle. If you want a service to handle authentication, you’d call it AuthService and it would exclusively deal with authentication, nothing more. If you decide that you need to handle user actions, you should create a new service called UserService .

Services should be DRY (Don’t Repeat Yourself)

Services are classes that are initialized through dependency injection.

To use a Service, inject the service as a dependency through the constructor , like constructor (private authService: AuthService) .

After this, you will have access to AuthService through this.authService .

Thinking about Services as the ‘business logic’ makes it easy to understand when to use one.

Although this is easy to conceptualize, Service’s can get complex.

Complexity in Services

Services get complex when they interact with each other and the rest of the application. A Services’ provider scope can be hard to understand at first.

Ultimately, there are two types of services:

Singleton

Non-Singleton

Singletons

Singleton Services are application-wide services with only one instance of the service in the application. This means that you’d share variables when using the Service in different components; you are using the same instance.

You’d create an application-wide service using the service decorator providedIn: 'root' . Or you could leave it as providedIn: 'any' and Angular will automatically instantiate it as a singleton, plus you benefit from tree-shaking if it is not used by the current bundle.

Non-Singletons

Non-Singleton Services can have multiple instances of the same service throughout the application. This means that you wouldn’t share variables when using the Service in two different components.

Using providers: [UserService] in the component or directive metadata (decorator) would provide a new instance of a Service.

Therefore, you can see where the complexity can arise, through the interaction between a singleton, non-singleton, and the rest of the application.

It’s important to make it obvious whether a Service is supposed to be a singleton or not. Most of your Services will likely be singletons, so this should limit the complexity somewhat.

2) Dynamic Template Engine

One of Angular’s main features is its’ unique HTML templates with integrated custom elements, resembling XML. The way you interact with these HTML templates is Angular-specific, and unlike interaction experienced in React or other popular frameworks. Angular provides custom attributes and HTML elements that enable dynamic rendering of HTML.

The reliance on Angular HTML elements means that there are a few new concepts to learn. These are ng-content , ng-container and ng-template . These provide different functionality to the DOM. However, what they have in common is that they all reference an element in the DOM.

These elements seem like magic until you fully understand how they work ‘under the hood’.

The difference between ng-content, ng-container, ng-template

They are used to indicate, to Angular, where to dynamically load components.

ng-content

This is used for content projection. It is essential for building reusable components. It allows you to extend and customize components by projecting into the component from the outside.

ng-container

This is the grouping element that does not interfere with the DOM. It is simply inserted where it is referenced. It is the easiest way to exclude and include HTML based on conditions and template expressions. You can reference ng-templates with ng-container in if else syntax and template variables.

ng-template

This is used to hold template references. You’d wrap a template in ng-template to conditionally insert it into the DOM by using its’ template reference.

Elements that are not shown through a condition are held as an ng-template until they are conditionally inserted.

Structural directives are the most useful methods of conditionally inserting elements into the DOM, based on the business logic and the application data.

They include:

NgIf

NgFor

NgSwitch

You can even write your own if these don’t give you the functionality you want.

As with any Single Page Application (SPA), dynamic rendering is at the core of the application. It describes the way HTML is dynamically inserted into the DOM. Understanding how Angular works under the hood makes developing an Angular application straight-forward and as predictable as it can be.

But again, Angular does a lot of things ‘under the hood’ to make your life easier as a developer. Therefore, things aren’t so predictable at first.

3) RXJS Baked-in

Throughout the Angular framework, there is a reliance on the RxJS library (JavaScript Reactive Extensions).

You can basically assume RXJS as part of Angular. The reason is that Angular itself is built using RXJS.

You cannot escape it.

Due to this, when you start to learn Angular, you immediately notice that there is an emphasis on reactive programming. It is a framework where Observables and Promises are ubiquitous. You’ll see Observables used in the HTTP client, Router events, and other Angular provided Services.

You’ll notice that you can’t get anywhere without having to deal with streams of data, which isn’t a bad thing.

However, it does force you to learn RxJS in-depth; specifically the way Angular interacts with data streams.

Although RXJS is great and is essential for reactive programming in Angular, it steepens the learning curve dramatically.

Learning RXJS on its own is time-consuming, so learning both Angular and RXJS is bound to be a daunting process.

The core RXJS concepts are easy to grasp, at first, but you are met by uncaught errors and days scratching your head, only to realize that you don’t have the solid grasp you thought on RxJS.

The inner workings of an RXJS operator will catch you out as your code begins to get more complex.

If you make assumptions about RXJS operators, you will eventually be caught out

This requires a shift in mindset if you’re not familiar with streams of data. Although RxJS is specific to JavaScript, ReactiveX, the library that includes implementations such as RxJS, Rx.NET, and RxJava, likely has an implementation for your language. So you may be familiar with reactive programming and dealing with data streams.

Dealing with data streams itself isn’t the difficult part. The difficult part is understanding how the operators work. It can be hard to get your head around how the RxJS operators transform the data streams and modify the behavior.

When debugging RxJS streams, it is not just the emitted data that you have to observe, it’s the order of emission, the timing, the type of data, and other aspects of its’ behavior.

This can make debugging your application difficult if you don’t fully understand RxJS. To debug your code, you have to understand the expected behavior, and how the actual behavior deviates from that, to be able to test effectively.

Reactive programming in Angular

Reactive Programming means thinking of everything as asynchronous, reacting to events that happen over time not necessarily in order. You think of data as coming from streams with Observables and Promises all the way to its destination.

In Angular, this means from the API all the way to the template.

The sooner you realise that everything should be a stream, the better

Realizing the importance of data streams before any real work goes into the application means you can use ‘RxJS x Angular’ best practices from the start, building a truly end-to-end reactive application.

End-to-end in this context means the data starts and ends as an Observable to be unpacked through the async Pipe in the templates; avoiding manual subscriptions.

Luckily, Angular is a framework that encourages reactive programming. While using RxJS with Angular, you will begin to realize that the async Pipe, which is part of the standard library, is one of your most-used Angular Pipes.

In Angular, the async pipe is the best tool in an end-to-end reactive application. Using data$ | async in your templates handles the subscription and un-subscription of observables automatically.

It is a well-known best practice in RxJS to prevent manually subscribing using subscribe() in the component class. The async pipe is the best tool to conform to this best practice. RxJS provides a comprehensive library with operators to transform, combine, create, and filter streams of data, so most of the time you should be able to work out a way to prevent manual subscriptions.

You need to learn the difference between Hot and Cold Observables, the marble diagram of RxJS streams, the different approaches to components (Smart or Dumb), and how to implement end-to-end reactive web applications.

The best place to start understanding RxJS is through learnrxjs.

If you’re more of a visual learner, a good way to visualize the data streams and RxJS operators is through the marble diagrams.

The marble diagrams show the order of emission and how the operators affect the behavior of observable data streams.

The biggest thing is the mindset shift

Due to the array of new concepts that Angular brings to web development, there is a required shift in mindset. The way Angular works encourages a reactive approach, coupled with RxJS as the reactive catalyst.

In addition to the new concepts, approaches, syntax, and RxJS, you have to think about the shadow DOM. The reason Angular has an ‘Angular way’ to do everything is because of the shadow DOM and the NgZone.

The NgZone is an execution context that persists across asynchronous tasks

Angular provides solutions when interacting with the DOM because it ensures that tasks are executed within the Angular Zone. This is important for change detection.

Tasks that aren’t executed inside the Zone are at risk of not being detected by Angular. This means that updates to the DOM won’t take place as they should due to how Angular uses the shadow DOM and NgZone.

The existence of the NgZone introduces an additional perspective to consider when developing your application. It means you have to think about tasks as either ‘in the zone’ or ‘out of the zone’.

It also means you can rarely deviate from Angular’s way of doing things without unknowingly creating a bug. It forces you to learn the Angular way of doing things and fully conform to Angular's’ approach to web development. Therefore, you can’t really put off learning about certain parts of Angular.

When starting to learn Angular, everything will seem unfamiliar at first, especially if you have come from a purely JavaScript background. If you are used to TypeScript, there will be some familiarity, but even you may not be spared.

Using Angular to build web applications is ultimately rewarding, but only once you’ve worked out what is ‘under the hood’.

What you should know before learning Angular

As a beginner learning Angular, cognitive overload will be a familiar mental state.

But once you’ve got to grips with the syntax, it is what is under the hood that will mess with you.

Unfortunately, you don’t know when it will trip you up, and the only way to know what is important in Angular is through experiencing it first hand.

This means failing over and over again. This requires patience.

But once you’ve worked it out, it all starts to make sense, and the rewards are huge.

Thanks for reading! Any questions, let me know in the comments.