Главная » Статьи » Полное руководство по созданию форм с автосохранением в Angular

Полное руководство по созданию форм с автосохранением в Angular

Полное руководство по созданию форм с автосохранением в Angular

От автора: приложение, показанное в статье, работает на RxJS и Angular Material.

Следующие команды создают новое приложение Angular, генерируют компонент, в котором есть форма с автосохранением, обслуживают приложение и открывают проект в Visual Studio Code.

ng new AutoForm --style=scss
ng g c auto-form
ng serve
cd AutoForm
code .

Заменяем содержимое app.component.html следующим:

<app-auto-form></app-auto-form>

Извините, <router-outlet> </router-outlet>, вы нам не нужны для этого.

Полное руководство по созданию форм с автосохранением в Angular

Вы увидите на localhost:4200

Добавление Angular Material

ng add @angular/material

Теперь импортируйте необходимые модули из Angular Forms и Angular Material в app.module.ts. Мне пришлось перезагрузить сервер, чтобы изменения вступили в силу.

...
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select'; @NgModule({ ... imports: [ ... FormsModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatSelectModule, ], ...
})
export class AppModule {}

Создание формы

Форма будет профилем с полями ввода для имени, пола и биографии.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-auto-form', templateUrl: 'auto-form.component.html', styleUrls: ['auto-form.component.scss'],
})
export class AutoFormComponent implements OnInit { profile: FormGroup; constructor(private formBuilder: FormBuilder) { this.profile = this.formBuilder.group({ name: [], gender: [], bio: [], }); } ngOnInit(): void {}
}

<h1>Profile</h1>
<form [formGroup]="profile"> <mat-form-field appearance="fill"> <mat-label>Name</mat-label> <input matInput formControlName="name" /> </mat-form-field> <br /> <mat-form-field appearance="fill"> <mat-label>Gender</mat-label> <mat-select formControlName="gender"> <mat-option value="m">Male</mat-option> <mat-option value="f">Female</mat-option> <mat-option value="o">Other</mat-option> </mat-select> </mat-form-field> <br /> <mat-form-field appearance="fill"> <mat-label>Bio</mat-label> <textarea matInput formControlName="bio"></textarea> </mat-form-field>
</form>

Группы форм имеют свойство Observable, называемое valueChanges, которое генерирует событие каждый раз, когда значение изменяется в одном из элементов управления формой. Этот Observable будет основой функции автосохранения.

В auto-form.component.ts подпишемся на valueChanges и добавим каналы RxJS для управления потоком автосохранения.

...
import { of } from 'rxjs';
import { debounceTime, switchMap } from 'rxjs/operators';
... ngOnInit(): void { this.profile.valueChanges .pipe( debounceTime(1500), switchMap((value) => of(value)) ) .subscribe((value) => { console.log(value); }); }
...

Но представьте, что of (true) на самом деле является наблюдаемой функцией, которая сохраняет данные формы в вашей базе данных, потому что это была бы реальная реализация этой функции автосохранения.

Операторы RxJS

debounceTime

Этот оператор не позволяет генерировать событие из Observable до тех пор, пока не пройдет установленный промежуток времени до последнего события. Другими словами, valueChanges не будет генерировать событие, пока профиль не будет изменен в течение 1,5 секунд подряд. Это предотвращает постоянные обновления базы данных, которые могли бы произойти, если бы событие запускалось после каждого отдельного изменения формы. 1,5 секунды основаны на ограничении одной записи в документ за секунду в Cloud Firestore.

switchMap

Этот оператор переключает Observable на новый Observable. Однако независимо от того, какую серверную технологию вы используете вместе с Angular, у вас почти всегда будет одна в службе, которая обновляет данные пользователя. В любом случае, это будет тот Observable, на который мы хотим подписаться. Этот оператор легко отменяет предыдущий Observable и подписывается на новый.

Улучшения UX

Черпая вдохновение прямо здесь, на Medium, когда я пишу эту статью, полезно видеть, когда моя работа сохраняется, а когда заканчивается. Давайте улучшим нашу форму, чтобы пользователь знал, что происходит, с помощью новой переменной saveStatus.

В auto-form.component.html добавьте переменную где-нибудь, чтобы пользователь мог ее увидеть.

{{ saveStatus }}

В auto-form.component.ts нам нужен новый оператор RxJS, tap, чтобы запускать функцию каждый раз при изменении элемента управления формы. Эта функция установит статус на «Сохранение». В Подписке, как только данные будут сохранены, этот статус будет установлен на «Сохранено», а через две дополнительных секунды, если статус все еще будет такой же — меняется на «Ожидание», что является пустой строкой.

...
enum SaveStatus { Saving = 'Saving...', Saved = 'Saved.', Idle = '',
} function sleep(ms: number): Promise<any> { return new Promise((res) => setTimeout(res, ms));
}
...
saveStatus: SaveStatus.Saving | SaveStatus.Saved | SaveStatus.Idle = SaveStatus.Idle;
... ngOnInit(): void { this.profile.valueChanges .pipe( tap(() => { this.saveStatus = SaveStatus.Saving; }), ... ) .subscribe(async (value) => { console.log(value); this.saveStatus = SaveStatus.Saved; await sleep(2000); if (this.saveStatus === SaveStatus.Saved) { this.saveStatus = SaveStatus.Idle; } }); }
...

А вот и рабочая демонстрация:

Полное руководство по созданию форм с автосохранением в Angular

Надеюсь, вы нашли это руководство полезным. Спасибо, что нашли время, чтобы прочитать статью.

Автор: Charlie Levine

Источник: javascript.plainenglish.io

Редакция: Команда webformyself.