Angular: CRUD con RxJs

Ejemplo CRUD con RxJs y Bootstrap 5

Generar nuevo proyecto, con opciones de router y scss habilitadas:


ng new lab-rxjs-crud-bootstrap --routing=true --style=scss

cd lab-rxjs-crud-bootstrap

Crear modulo 'lab' con opciones de router

ng g m lab --routing

Crear componentes, servicio e interface (modelo) para consumir api rest

ng g c lab/components/UserList --skip-tests
ng g c lab/components/UserForm --skip-tests

ng g service lab/services/User --skip-tests

ng g interface lab/models/User

La interface que representa el modelo de datos tiene el siguiente aspecto:


export interface User {

    id?: number;
    documentId: string;
    firstName: string;
    lastName: string;
    gender: string;
    emailAddress: string;
    phoneNumber?: string;    

}

El servicio implementa el observable de tipo BehaviorSubject de RxJs para mantener la lista de elementos actualizada (userListSubject). En los metodos de crear, modificar y eliminar se utiliza el operador tap para actualizar la lista de elementos.

También se utiliza BehaviorSubject para tener disponible el ultimo elemento 'User' actualizado (userSubject).


@Injectable({
  providedIn: 'root'
})
export class UserService {

  private userListSubject: BehaviorSubject<Array<User>>
  private userSubject: BehaviorSubject<User>;

  private apiUrl = environment.API_URL;
  private httpHeaders: HttpHeaders;

  private dataSource = {
    items: Array<User>(),
    error: ''
  }  

  constructor(private httpClient: HttpClient) { 
    
    this.userListSubject = new BehaviorSubject<User[]>([]);
    this.userSubject = new BehaviorSubject<User>({} as User);

    this.httpHeaders = new HttpHeaders({
      'Content-Type' : 'application/json'
    });    
  }

  public get users() : Observable<Array<User>> {
    return this.userListSubject.asObservable();
  }

  public getUser(): Observable<User> {
    return this.userSubject.asObservable();
  }

  public setUser(user: User) {
    this.userSubject.next(user);
  }

  public unsetUser() {
    this.userSubject.next({} as User);
  }


  public loadUsers(): void {

    let url = this.apiUrl + '/users/?page=1&size=50&order=asc';
    this.httpClient.get<User[]>(url, {headers: this.httpHeaders})
      .subscribe( items => {
        this.dataSource.items = items;
        this.userListSubject.next([...this.dataSource.items]);
      }, 
        error => console.log(`[x] error: ${error}`)
      );
    
  }

  public addUser(user: User): Observable<User> {
    
    let url = this.apiUrl + '/users';
    return this.httpClient.post<User>(url, user, {headers: this.httpHeaders})
              .pipe(
                tap( res => {
                  this.dataSource.items.push(res);
                  this.userListSubject.next([...this.dataSource.items]);
                })
              );

  }

  public updateUser(user: User) {

    let url = this.apiUrl + '/users';
    return this.httpClient.post<User>(url, user, {headers: this.httpHeaders})
              .pipe(
                tap( res => {
                  
                  this.dataSource.items = this.dataSource.items.map( x => {
                    if (x.documentId === res.documentId) {
                      x.firstName = res.firstName;
                      x.lastName = res.lastName;
                      x.gender = res.gender;
                      x.emailAddress = res.emailAddress;
                      x.phoneNumber = res.phoneNumber;
                    }
                    return x;
                  })
                  this.userListSubject.next([...this.dataSource.items]);
                })
              );

  }


  public deleteUser(user: User) {

    let url = this.apiUrl + '/users/' + user.documentId;
    return this.httpClient.delete<User>(url, {headers: this.httpHeaders})
            .pipe(
              tap( res => {
                this.dataSource.items = this.dataSource.items.filter(item => item.documentId !== user.documentId);
                this.userListSubject.next([...this.dataSource.items]);
              })
            );

  }

}

Puedes descargar el código fuente completo de este ejemplo desde los siguientes enlaces:




¿Tienes alguna consulta?
Puedes contactarme enviándome un mensaje desde aquí.