Simple state management in Angular?

Viewed 2840

I'm learning Angular from the very beginning, and coming from React, I can't find a way to manage a simple state in Angular. It's a simple todo app, and my strategy is to create a Todos array in todo.service.ts

@Injectable()
export class TodoService {
  todos: Todo[] = [
    { id: 0, title: 'Cooking', completed: false }
]
  nextId: number = 1;
  constructor() { }
  public getTodos(): Todo[] {
    return this.todos;
  }
  public addTodo(title: string): any {
    this.newTodo = new Todo({ id: this.nextId, title, completed: false })
    this.todos.push(this.newTodo);
    this.newTodo = new Todo();
    this.nextId++
  }
  public deleteTodo(chosenTodo: Todo): any {
    this.todos = this.todos.filter(todo => todo.id !== chosenTodo.id)
  }
}

Now on the ListingComponent, I want to get all Todos, and then pass it down to ListingItemComponent, as such

todos: Todo[] = []
  todoTitle: string = '';
  constructor(private todoService: TodoService) { }
  ngOnInit(): void {
    this.todos = this.todoService.getTodos();
    this.todoTitle = 'Do Something';
  }

  addTodo() {
    this.todoService.addTodo(this.todoTitle);
  }
<div *ngFor="let todo of todos">
  <todo-listing-item [todo]="todo"></todo-listing-item>
</div>
/* This just adds a todo with title 'Do Something' for testing */
<button (click)="addTodo()">Add Todo</button>

Finally in ListingItemComponent

  @Input() todo: Todo
  constructor(private todoService: TodoService) { }

  ngOnInit(): void {
  }
  deleteTodo(): void {
    this.todoService.deleteTodo(this.todo)
  }
<h1>{{todo.title}}</h1>
<button (click)="deleteTodo()">Delete Todo</button>

Now the component has no error, and I made sure to declare everything, but it's not working. Clicking the button won't change anything. After digging in, I changed the ListingComponent into "let todo of todoService.getTodos()", and remove the todos in the ts file along with the ngOnInit, and somehow it works. My guessing is that the ListingComponent doesn't know that the todos array has changed, and so it's not rerendering?

  1. So if I was to initialize the todos in the ngOnInit like I did before, do I need some other life-cycle to listen to the change of todos?
  2. If many components need the todos array, should I write ngOnInit(): void { this.todos = this.todoService.getTodos();} on every single one of them? And if one component changes their todos, can other components listen and rerender as well?

    Thank you for reading. In React I would just create a global state, along with the functions, and pass it as props down to every child. But I can't wrap my head around managing state in Angular. Is it because I'm thinking in React, while I should not?

4 Answers

Let me first say that I'm a huge fan of NGRX and the pattern, and I suggest you make this part of your learning path. However, if you're looking for simple state management than a simple Observable will do the trick.

I created a stack overflow to illustrate the technique using the code you provided: https://stackblitz.com/edit/angular-ivy-kfw1sd. In this demonstration, I'm leveraging BehaviorSubject which is a special type of observable.

In closing, do your best to avoid .subscribe() and use the async pipe instead.

Hope this helps, Isaac

If you want to have a simple global state, you can start using Shared Services, obviously it will be only for learning purposes, because if you want to use in a real project, you can use Shared Services, but also, you would need Facade or other Design Patterns.

Main advantage using Facade is that you can migrate to NgRx easier.

I have an example using API + State + Base Architecture: https://github.com/cmandamiento/angular-architecture-base

Feel free to reach me out.

Angular Architecture

Indeed you do not always need to add another Library to manage state in Angular. Angular comes with RxJS out of the box...

All the well known state management libraries use RxJS/BehaviorSubject internally. This article shows how to write a simple DIY state management Class which can be extended by Angular services.

Simple yet powerful state management in Angular with RxJS

This solution is also based on RxJS/BehaviorSubject.

Maybe it can be useful for you. The code example in the article is a Todo App :)

Related