Storing State in an Angular Service
In the last lesson, we set up a form component that would emit an event that
includes the data that the user entered into the form. We are using that form
component in our HomeComponent
now, but all we are doing is logging out the
value from the form.
Now we actually need to do something with it. This is going to be our first experience with dealing with state in the application. We have an entire module dedicated to state coming up soon. Of course, we are going to discuss what state is and what it looks like in detail in that module, but it is useful to have a basic idea now.
A Quick Intro to State
Let’s use a real analogy. Consider a hammer, a hammer does not have state (we probably could consider a hammer to have state, but let’s keep things simple). Consider a light bulb, a light bulb does have state — it can be in the on state or the off state.
When we first load our application it is in its default state. At the moment, that is the only state our application can be in because there isn’t anything that modifies our application’s state yet (without getting too technical). A user enters some data into a form, submits it, but nothing happens. However, we do want something to happen.
We want to add a feature so that the data the user enters is remembered and displayed in the form of a todo in a list. When we do this, the application’s state will have changed because now we have some data in memory. The application has changed in some way.
When thinking of state, think of a lightbulb, or a traffic light, or a computer. In what ways can our application be interacted with (internally or externally) to change the way it behaves/what it stores in memory? Generally, the state of an Angular application refers to the data that is being stored in memory (i.e. the stuff that will be lost when the application is refreshed).
Storing State in a Service
We have some todo data that we are handling, and we want that as part of our application’s state somehow. Specifically, we want to store the data in memory and use that data to display a list of all the todos that have been added.
This is where we will reach for a service (i.e. an @Injectable()
class).
If you remember from the basics section, a service can be shared with our entire
application. It’s a great way to share data between components, and store data
that we want to persist throughout the life of the application.
This service is going to have a publicly exposed signal. We can then use that signal from anywhere in the application, and can react any time it is updated with a new value.
This signal will only retain its value for as long as the app runs. As soon as we refresh the application our service is going to be destroyed along with any data in memory. If we want to persist data in memory, we will need to use some kind of external storage mechanism and then re-initialise our state upon loading the application. This is a challenge we will tackle in our “real” application walkthrough later.
Create the following service at
shared/data-access/todo.service.ts
:
import { Injectable, signal } from '@angular/core';
import { Todo } from '../interfaces/todo';
@Injectable({
providedIn: 'root',
})
export class TodoService {
// We only want this class to be able to
// update the signal (# makes it private)
#todos = signal<Todo[]>([]);
// This can be read publicly
todos = this.#todos.asReadonly();
addTodo(todo: Todo) {
this.#todos.update((todos) => [...todos, todo]);
}
}