Skip to content

Instantly share code, notes, and snippets.

@MirzaLeka
Last active July 16, 2023 19:13
Show Gist options
  • Select an option

  • Save MirzaLeka/f322b29689b66f737aea6fd2dfeec896 to your computer and use it in GitHub Desktop.

Select an option

Save MirzaLeka/f322b29689b66f737aea6fd2dfeec896 to your computer and use it in GitHub Desktop.
Angular Reactive Form

Using Local Storage with Observables in Angular

Key Files:

  • todo-form.module.ts
  • todo-form.component.ts
  • todo-form.component.html
  • local-storage.service.ts
import { Injectable } from '@angular/core';
import { EMPTY, Observable, of, Subscriber } from 'rxjs';
import Todo from '../model/todo.model';
@Injectable({
providedIn: 'root'
})
export class LocalStorageService {
private get state(): Storage {
return window.localStorage;
}
private get generateTodoKey(): string {
return Math.random().toString(36).slice(2) + Date.now();
}
getStateItems() {
const entries = Object.entries(this.state);
return of(entries);
}
getSingleItem(key: string): Observable<Todo | null> {
const item = this.state.getItem(key);
if (!item) return of(null);
const todo: Todo = JSON.parse(item);
return of(todo);
}
saveToState(value: Todo): Observable<unknown> {
return new Observable((observer: Subscriber<unknown>) => {
this.state.setItem(this.generateTodoKey, JSON.stringify(value));
observer.next();
observer.complete();
})
}
deleteStateItem(key: string): Observable<null> {
this.state.removeItem(key);
return EMPTY;
}
deleteAllItems(): Observable<null> {
this.state.clear();
return EMPTY;
}
}
<form [formGroup]="todoForm" (ngSubmit)="onSubmit()">
<div class="title-wrapper">
<input formControlName="title" type="text" />
<div class="error-message" *ngIf="isInvalidTitle">Please fix your input!</div>
</div>
<div class="description-wrapper">
<textarea formControlName="description"></textarea>
<div class="error-message" *ngIf="isInvalidDescription">Maximum number of characters is 300!</div>
</div>
<button class="submit-btn" type="submit">Submit</button>
</form>
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { filter, take } from 'rxjs';
import { LocalStorageService } from 'src/app/services/local-storage.service';
@Component({
selector: 'app-todo-form',
templateUrl: './todo-form.component.html',
styleUrls: ['./todo-form.component.scss'],
})
export class TodoFormComponent implements OnInit {
todoForm!: FormGroup;
@Input()
todoId!: string;
constructor(private fb: FormBuilder, private service: LocalStorageService) {}
ngOnInit(): void {
this.setupForm();
this.populateForm()
}
get isInvalidTitle(): boolean {
const titleControl = this.todoForm.get('title');
if (!titleControl) return false;
return titleControl.invalid && (titleControl.dirty || titleControl.touched);
}
get isInvalidDescription(): boolean {
const descriptionControl = this.todoForm.get('description');
if (!descriptionControl) return false;
return descriptionControl.invalid && (descriptionControl.dirty || descriptionControl.touched);
}
private populateForm() {
if (!this.todoId) return;
this.service.getSingleItem(this.todoId)
.pipe(
filter(data => !!data),
take(1)
)
.subscribe(savedItem => {
this.todoForm.patchValue({
title: savedItem?.title,
description: savedItem?.description
})
})
}
private setupForm(): void {
this.todoForm = this.fb.group({
title: ['', [Validators.required, Validators.maxLength(100)]],
description: ['', [Validators.maxLength(300)]],
});
}
private triggerValidationOnSubmit() {
Object.keys(this.todoForm.controls)
.forEach((field: string) => {
const control = this.todoForm.get(field);
control?.markAsTouched({ onlySelf: true });
});
}
onSubmit(): void {
if (!this.todoForm.valid) {
this.triggerValidationOnSubmit();
return
}
console.log('done')
// this.service.saveToState(this.todoForm.value).subscribe();
}
}
import { NgModule } from '@angular/core';
import { TodoFormComponent } from './todo-form.component';
import { ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [
TodoFormComponent
],
imports: [
CommonModule,
ReactiveFormsModule
],
exports: [
TodoFormComponent
]
})
export class TodoFormModule { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment