blog.hipsquare.net

Angular Renaissance

Cover Image for Angular Renaissance
Zuzana Kurillova
Zuzana Kurillova

Nowadays, it is very exciting time to be an Angular developer. Every couple of weeks there is a new concept introduced. Part of the community loves it, part is more conservative and rather sticks with the old way of Angular programming. In HipSquare we also want to understand what is beneficial for us and gladly accept the new convenient styles that all belong to so called Angular Renaissance.

Goal of this article

In this article, we will introduce new programming concepts introduced in the latest releases of Angular. We will show simple examples and discuss how can they be beneficial for your developer experience.

Prerequisites

For the article, we assume some basic knowledge of what TypeScript and Angular is, as well as how very basic frontend development works.

Rome wasn't built in a day

Such as Rome was once the capital of a super power nation, Angular used to be the ruler of the frontend development community. However, nothing lasts forever and soon enough couple of frameworks as well as libraries started to pop around the frontend universe. Nowadays we all know, who is the popularity king of the playground - React, with its easy to start nature. But it's not the only one competing for the audience: Vue, Svelte, and others are also trying to share the pie. Just look at the npm installs of React, its super organized sister Angular and fast and cool brother Vue:

React winning

The main reason why Angular is not adapted by many seems to be the steep learning curve. The framework is rich and stable, however at times robust and the developers might have struggled with boilerplate code. The framework needed an update - and so, Rome alike, the renaissance movement was (re)born.

Google Angular Team claims: “A big part of the (renaissance) movement was this humanist aspect of human growth and human potential. This movement in Angular focuses on the developer experience and the human potential to use Angular and make it more friendly to all users.”[1]

Within couple of months this year and the last one, plenty of new concepts have arrived to make this happen, especially the 3 main changes:

1. Moving Off Modules (standalone components)
2. Adding Signals
3. Control Flow

Moving Off Modules (Standalone components)

The modules that grouped all the imports, exports, providers for the set were removed and each part of code now only imports dependencies (components, services, pipes, directives…) that it needs, not whole modules. This makes the system more lightweight - the bundles are smaller. And not only that.

Angular Google Team: “It makes us (…) more compatible to other JavaScript developers. If they need to quickly jump on an Angular project — because there’s a lot of teams that have an Angular project, or a React project or a Vue project — it makes it easier for people to grok our framework, because the base pieces, the Legos, look the same.”[1]

Adding Signals to Angular = reactivity in a new way

As of definition, signal is a built-in primitive for reactivity. For a non-programmer, reactivity is something that everyone knows from Excel sheets. If we use a sum operator - and we change one of the rows within the summed rows, the sum changes too.

Angular already used ways to support reactivity before, let's mention for example Observables, but signals just do it more elegantly.

The most visible usecase for the signal use is within the state management. Once the value of the state changes, all the values of any responsive elements change too.

Let me show a piece of code here where the NGRX signal store is used to keep track of the state for a simple chatbot. We keep track of the messages and the boolean value of user isTyping or not. From that the computed values are used to filter only the bot's or user's messages. The state values are changed within the method. Super pure and simple way - and centrally shared. Every component or service can simply reach out for the store - and its states. And only updated when they are needed, which makes them faster.

export const chatbotStore = signalStore(
  withState<ChatbotState>({
    messages: [],
    isTyping: false
  }),
  withComputed(({ messages }) => ({
    usersMessages: computed(() =>
      messages().filter((message) => message.author === ChatbotUser.USER)
    ),
    botsMessages: computed(() => messages().filter((message) => message.author === ChatbotUser.BOT))
  })),
  withMethods((store) => ({
    addMessage(message: ChatbotMessage): void {
      patchState(store, {
        messages: [...store.messages(), message]
      });
    },
    setMessages(messages: ChatbotMessage[]): void {
      patchState(store, {
        messages: messages
      });
    },
    setIsTyping(value: boolean): void {
      patchState(store, {
        isTyping: value
      });
    }
  }))
);

No more change detection is needed and the time might come, that Observables will not be needed at all. Life is so easy...

Control flow

Last but not least, brand new control flow. Forget *ngIf, *ngFor, *ngSwitch within the template. The new elegant way is very similar to the javascript[4] way of code organization. It's heavily inspired by Svelte[1] and not only it looks better - it is faster too, as the unused elements are skipped. Just a few examples:

Old-school "if" (*ngIf):

<div *ngIf="loggedIn; else anonymousUser">
  The user is logged in
</div>
<ng-template #anonymousUser>
  The user is not logged in
</ng-template>

New "if" (@if):

@if(loggedIn){
  The user is logged in
} @else {
  The user is not logged in
}

Old-school "for" (*ngFor):

<div *ngFor=“let user of users”>
  {{ user.name }}
</div>
<div *ngIf=“!users”>
  Empty list of users
</div>  

New "for" (@for):

@for (user of users; track user.id) {
  {{ user.name }}
} @empty {
  Empty list of users
}

Old-school "switch" (*ngSwitch):

<div [ngSwitch]="accessLevel">
  <admin-dashboard *ngSwitchCase="admin"/>
  <moderator-dashboard *ngSwitchCase="moderator"/>
  <user-dashboard *ngSwitchDefault/>
</div> 

New "switch" (@switch):

@switch (accessLevel) {
  @case ('admin') { <admin-dashboard/>}
  @case ('moderator') { <moderator-dashboard/>}
  @default { <user-dashboard/>}
}

One change stands out even more from the others: deferred views. The easy way to take care of lazy loading components. As they are loading, the placeholder image can be shown. The case of error is taken care of, as well.

@defer (on viewport) {
  <lazy-loading-component/>
} @loading {
  Loading…
} @error {
  Loading failed :(
} @placeholder {
  <img src="comments-placeholder.png">
}

Brand new extra improvement - signal models

I want to add one more extra developer experience convenience that was brought just couple of days ago and that are signal models. These help us get rid of boilerplate around @Inputs and @Outputs, simply using signals. Just look at this simple example of the new and old code:

Old-school "@Input, @Output":

export class ChildComponent {
   @Input({required: true})
   valueFromParent : string = '';
   
   @Output() 
   valueFromParentChange = new EventEmitter<string>();

  
   updateValue() : void {
    this.valueFromParentChange.emit('Send updated value');
   }
}

New signal model:

export class ChildComponent {
   valueFromParent : ModelSignal<string> = model.require<string>();
   
   updateValue() : void {
    this.valueFromParent.update(() => 'Send updated value');
   }
}

Conclusion

As the city of Rome was resurrected after the dark medieval ages, let's hope the renaissance of Angular will regain it the popularity that it deserves. In our Brown Bag Sessions in HipSquare we had a fruitful discussion after the presentation about the changes that we welcome, like the control flow changes or signals. But also the changes that don't look always as the best solutions, like the standalone components vs. the modules. What would be your opinion about the new concepts? Angular Renaissance is here, so let's get the best out of this new developer experience.

Angular Renaissance

Sources

  1. Loraine Lawson: The Angular Renaissance: Why Frontend Devs Should Revisit It, interview with the Google Angular Team member Alyssa Nicoll (https://thenewstack.io/the-angular-renaissance-why-frontend-devs-should-revisit-it/)
  2. Abhijeet: React vs. Angular vs. Vue: A Comparative Analysis For 2024 (https://themeselection.com/react-vs-angular-vs-vue/)
  3. Lulëzim Ukaj: Die Angular 17 Renaissance (https://angular.de/artikel/angular-17-eine-renaissance/)
  4. Minko Gechev: Introducing Angular v17 (https://blog.angular.io/introducing-angular-v17-4d7033312e4b)