What I should have known when starting to write angular 🔥
Tags: angular, webdev
Published: 2023-05-02 13:29:19

I have written angular for some years now and I am still learning. I know Angular is the framework everyone loves to hate, the Java of the frontend world. However, the likelyhood of ending up in an angular project is quite high. Let me take you through my most important tips to becoming a good angular developer.

## No logic in your components
A component in angular has three files that should be focusing on rendering and only rendering. If you start adding a lot of business-logic into that component-code you will end up with code that is overly complicated and tests that are hard to maintain. If your component.ts-file exceeds 250 lines of code, it is time to rethink and refactor. Put logic into a service or event split the component into several smaller components.

## Features === Modules
I remember my first angular project. It had one module in it. That is wrong on so many levels and my rule of thumb is that you should make modules for every new feature. And there should be no cross-feature imports.

## RXJS is your friend
RXJS is a great tool for syncing major state of an application. State like the chosen project across the whole application. I remember doing a lot of subscriptions in my first application. And subscribing is not very good, let angular handle subscriptions. Below there are two examples:

### Bad usage of observables
This example is using subscribe and is in my mind "duplicating" data and we even have a memory leak if the observable does not complete.

```typescript
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-bad',
  template: `
  <ul>
    <li *ngFor="let idea of data ">{{ idea.name }}</li>
  </ul>
  `,
  styles: []
})
export class BadComponent  {

  data: Idea[];

  constructor(private ideaService: IdeaService) {
    this.data$ = ideaService.getGoodIdeasFromAlv().subscribe(data => this.data = data);
  }
}
```
### Good usage of observables
This example is using the async-pipe and is much cleaner. No memory-leaks as angular is removing the subscription for us. the code is also more readable.

```typescript
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-good',
  template: `
  <ul>
    <li *ngFor="let idea of data$ | async">{{ idea.name}}</li>
  </ul>`,
  styles: []
})
export class GoodComponent  {

  data$: Observable<Idea[]>;

  constructor(private ideaService: IdeaService) {
    this.data$ = ideaService.getGoodIdeasFromAlv();
  }
}
```

### Quick tips about RXJS
- Learn how to use `map`, `switchMap`, `share`, `shareReplay` `mergeMap`-operators
- Learn why `shareReplay` can create memory-leaks
- The less Behaviour-subjects / subjects you use, the better. Always rethink when adding new ones. You should hardly use any.
- When using `switchMap`/`mergeMap` you should carry the initial state. Trust me, it will make code scale in the future.
```typescript
class ExampleService {
  exampleId$ = BehaviourSubject(0);
  exampleResult$: Observable<{id: number, examples: string[]}>;

  constructor(private readonly httpClient: HttpClient) {
    this.exampleResult$ = this.exampleResultObservable();
  }

  private create exampleResultObservable() {
    exampleId.pipe(
      switchMap(id => this.httpClient.get(`somebackend/${id}`).pipe(map(response => ({
id,
examples: response,
}))
    )
  }
  
}
```

## A few quick tips to complete the article

### Use reactive forms
Your solution is not as good as what comes from `@angular/forms` 

### Give your loops an index
This increases rendering performance. Use the `trackBy`-directive and thank me when your project scales.

### Use pipes instead of functions
If you have a function in your component, formatting values, consider using a pipe instead. It is reusable and the performance is better.

### ChangeDetection set to `onPush`
If you manage to follow the "good" example above, all your component state will be reactive. Using onPush makes change detection more conservative and more efficient.

```typescript
@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
```

## Have I missed something?
Feel free to pass a comment and I might include your suggestions