VAN
DEL
.IO

Coming home to Angular



Reactive frameworks <3

I have been through the major 3: Vue, React and Angular – Both professionally and for fun personal projects.

And recently someone asked if, what I actually prefer… ?

My answer was vage because I found them equally useful for the specific cases I used them for in that specific area of my tech journey.
And at the point of picking a framework – we in the different teams – decided on that specific framework, based on the criteria we had outlined related to the specific project we were making.

Vue was the first on I worked with in a professional setup – and we picked it specifically because it was marketed as a micro framework compared the other major 2.
And the specific project use case we had in mind, was a tiny app that should be added on top of a legacy system.

Then i did some minor Angular apps in spare time, and later some a few React apps – simply to compare them.

In my following employments, which spanned across a wider field of UX/UI design to Frontend Development.
I created both React and Angular Apps, sometime switching in the same company based on the active project we worked on, so i have been switch back and forth way too much, if i have to say.

But now I have had some time to think about it – and also started rewriting an old Ionic app to pure Angular using signals – and I realised that I really like the way Angular works.

Jumping back and forth between those frameworks, is not prefered:
But on the other hand, it can also be a huge benefit.

By sticking with a specific framework, you get to know all the quirks and the little tricks for optimisations and they stick in your mind – but you dont know what you are missing out of from the other frameworks.

By switching between them based on project requirements (company decision or your own?), gives you a flexible mind – instead of framework specific knowledge and you gain general knowledge about reactivity, flows, patterns and approaches instead – also not limiting yourself to a single framework, give you way more options in the future – but you will never become a super master developer in a specific framework this way – unless you choose to walk that path.

Choose you battles, but stay open minded.

Now i have decided. After spending a lot of time in each framework – I want to stay in NG land.
I want to become the guru of angular – so now i am forcing myself to get re-familiar with angular, getting all the concepts freshly into mind again.
And it really does feel like coming home again, even though A LOT have changed.

 

Installing angular dependencies

I got completely used to just directly install npm deps, and then handle the following configuration based on the specific documentation.

npm i package@version

That I completely forgot about all the awesome built in angular stuff like:

ng generate

To ensure consist creation of files.

ng add

Which automates some of the setup of deps though cli, like adding config file, writing changes to angular.json etc..
I love it.
TODO: I still need to understand if ng add understands the version requirements or if it just installs the latest from package if a version is not explicitly defined..

$ ng add @angular-eslint/schematics
✔ Determining Package Manager
  › Using package manager: npm
✔ Searching for compatible package version
  › Found compatible package version: @angular-eslint/schematics@21.0.1.
✔ Loading package information from registry
✔ Confirming installation
✔ Installing package
    
    All angular-eslint dependencies have been successfully installed 🎉
    
    Please see https://github.com/angular-eslint/angular-eslint for how to add ESLint configuration to your project.
    
    We detected that you have a single project in your workspace and no existing linter wired up, so we are configuring ESLint for you automatically.
    
    Please see https://github.com/angular-eslint/angular-eslint for more information.
    
CREATE eslint.config.js (1004 bytes)
UPDATE package.json (1177 bytes)
UPDATE angular.json (3194 bytes)
✔ Packages installed successfully.

Standalone, Standalone, Standalone…

No more NgModule required, as standalone components manages its own dependencies.

Need to deep dive more on this topic to fully understand what standalone does.

 

Lazy-loading standalone components in routes

use

loadComponent:() => import('./the.component').then(m => m.TheComponent)

 

Signals

state management ? seems like an observable – subscribe pattern, without all the fuzz.
Set it, get it – update it.
Isolated or as globals.

const firstName = signal('Morgan');
const firstNameCapitalized = computed(() => firstName().toUpperCase());

I like it
And i think i found my currently preferred why of using it already – but maybe that will change.

 

Using globalSignals with setters – here in a QnA project as example

interface GlobalState{
   allTopics: Topic[];
   allQuestions:Practice[];
   ...
}

const initialState = {
  allTopics: [
    {...PracticeTopic, practices: Practices, levels: Levels},
    {...SpanishPracticeTopic, practices: SpanishPractices, levels: SpanishLevels},
    {...ChemestryPracticeTopic, practices: ChemestryPractices, levels: ChemestryLevels}
  ],
  allQuestions: [],
  ...
}

We set the global state as private readonly globalState = signal(initialState);

And then define the specific signals like : allTopics, which is computed values based on the globalState.

 

export class GlobalStateService {
  // Writable Signal (Private) - The actual state
  private readonly globalState = signal(initialState);

  // Read-Only Signals (Public) - The selectors
  // Components read these to ensure they can't accidentally write to the state.
  readonly allTopics: Signal<Topic[]> = computed(() => this.globalState()?.allTopics);
...

when we want to mutate the state, we call a specific setter for each action, and use globalState to update the signal value


// Methods for State Updates (Public) - The actions/mutations
  setCurrentTopic(topic: Topic) {
    this.globalState.update(state => ({
      ...state,
      currentTopic: topic
    }));
  }

...


In a component when we want to use the signal, we inject the GlobalStateService and define the variable to hold the signal
(notice we dont use caller () on the signal here when we define it, and it will inherit the type Signal<Topic> from globalState)



state = inject(GlobalStateService);
  selectedTopic = this.state.currentTopic;
...


someMethodInComponent(){
  //using the signal value
  const topicSignalValue = this.selectedTopic();
  if(topicSignalValue !== undefined){
    console.log(topicSignalValue +' is present')
  }
}

The reason i check for undefined before using any signal value, is because i choose to also use Union types, as the initial value of the signal is undefined until set – my union type looks like this


export interface Topic {
    id:string, 
    title:string, 
    subtitle:string, 
    practices: Practice[], 
    levels: Level[]
} 
// Ensures the default undefined is already represented
export type TopicObject = Topic | undefined;

I am not sure this is the most optimal way, but i dont like defining default undefined types in all components where i need to use something that could be undefined.

 

Change Detection Optimizations

default strategy is CheckAlways, which checks all components in the component tree

Optimize with:
changeDetection: ChangeDetectionStrategy.OnPush,

It ensures components only updates if:

 

TrackBy in *ngFor to reduce unnecessary checks

<div *ngFor="let item of items; trackBy: trackById">
  {{ item.name }}
</div>

trackById(index: number, item: any): number {
  return item.id;
}

 

No Function calls in Templates

Always use signals or
getters instead

get computedValue(): number {
  return this.data * 10;
}

 

Input Props & Binding dynamic values

 

Setting input properties on components

Before implementing Input Output stuff in components, imagine using signals for it instead

[attributes]  [properties]

is catched in component with
@Input() prop: number;

 

Setting events on components

(eventListeners)=”doSomething()”

 

 

Ensure efficient input changes

 

use ngOnChanges

Using ngOnChanges to catch the changes
ngOnChanges(changes: SimpleChanges) {
// changes.prop contains the old and the new value...
}

Input Setters

Setting data from UI

@Input() set data(value: any) {
  this._data = value;
}