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

100-6598647

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

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

JavaScript ng new AutoForm –style=scss ng g c auto-form ng serve cd AutoForm

code .

12345 ng new AutoForm –style=scssng g c auto-formng servecd AutoFormcode .

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

1

Извините, , вы нам не нужны для этого.

1-3911741

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

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

JavaScript ng add @angular/material

1 ng add @angular/material

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

JavaScript … 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 {}

12345678910111213141516171819 …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 {}

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

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

JavaScript 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 {}
}

123456789101112131415161718192021 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 {}}

Стек и очередь в JavaScript

Profile

Name
Gender Male Female Other
Bio

123456789101112131415161718192021

Profile

      Name        
      Gender          Male      Female      Other        
      Bio      

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

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

JavaScript … 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); }); }

12345678910111213141516 …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 и подписывается на новый.

Публиковать твиты на сайтах WordPress стало легче

Улучшения UX

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

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

JavaScript {{ saveStatus }}

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

JavaScript … enum SaveStatus { Saving = ‘Saving…’, Saved = ‘Saved.’, Idle = ”,

}

function sleep(ms: number): Promise { 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; } }); }

12345678910111213141516171819202122232425262728293031 …enum SaveStatus {  Saving = ‘Saving…’,  Saved = ‘Saved.’,  Idle = ”,} function sleep(ms: number): Promise {  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;        }      });  }…

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

2-4579664

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

Автор: Charlie Levine

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

Источник