Angularフォームを使用するためのより良い方法

「大いなる力には、大いなる力には大いなる力があります」—あなたは誰を知っていますか。それは本当です!Angular Formsは強力であるだけでなく、コントローラーに大きな混乱を引き起こします。FormBuilder、FormGroup、FormControl、ロジックの保存、ロジックの更新—ほとんど狂気。今日は、フォームを管理し、正気をもたらす方法を紹介します。

サービスを入力してください—それらは注射可能であり、必要なときに提供されます。それなら、フォームを管理するためにサービスを使用してみませんか?それでは始めましょう。

最初のステップ:インターフェース

まず、インターフェースを作成する必要があります。このデモでActorは、2つのインターフェイスを作成します。これは最終的なエンティティでありActorCreateInput、フォーム入力の形状です。

2番目のステップ:サービス

ルートに挿入されない、つまり{ providedIn: 'root' }デコレータに渡されないActorCreateFormServiceを作成します。

これまでのところ、すべてが自明です。この段階では、サービスはFormGroupを作成し、それをformクラスプロパティに割り当てる以外は何もしません。フォームの値と有効性を取得するための便利なメソッドをいくつか追加しました。

アクターを保存または更新するには、HTTPサービスに接続する必要があります。その仕事をするActorApiServiceがあるとしましょう。だからそれを注入します:

constructor(
    private fb: FormBuilder,
    private actorApiService: ActorApiService,
) {}

次に、アクターを作成および更新するためのいくつかのメソッドを記述しましょう。

データベースからアクターをロードしてフォームに入力するには、最後の1つのメソッドが必要です。これは、アクターを編集する必要がある場合に便利です。

3番目のステップ:コントローラー

コンポーネントでどのように使用できるかを見てみましょう。で提供しなかったためroot、正しいスコープ(通常はコンポーネント)で提供する必要があります。

コントローラがどれほどきれいであるかに注目してください。さらに、他の場所でも同じフォームサービスを使用できます。

最終ステップ:抽象サービス

まだ終わっていません。よく見ると、フォームサービスには、他のフォームにも使用できる再利用可能な部分がいくつかあります。たとえば、MovieCreateFormServiceです。それでは、フォームクラスをさらに一歩進めて、抽象化してみましょうAbstractFormService。デコレータを含める必要がなくなりました@Injectable():(簡潔にするために一部のコードは省略されています)。

次に、MovieCreateFormServiceを作成して拡張します。

これで、フォームを実現するために4つのメソッドをオーバーライドする必要があります。フォームの送信時に、保存、更新、リセットを自動的に処理します。MovieCreateFormServiceこれで、以前と同じように使用できActorCreateFormServiceます。

最終的な考え

このアプローチについてどう思いますか?このパターンにより、アプリケーション全体で多くのLOC(コード行)が節約されると思います。しかし、潜在的な問題や改善についての考えを共有してください。

読んでくれてありがとう!

完全なコード

import { FormBuilder, FormControl, FormGroup } from '@angular/forms'
import { Observable, throwError } from 'rxjs'

export abstract class AbstractFormService<T, InputT extends { id?: string }> {
    form: FormGroup

    constructor(protected fb: FormBuilder) {
        this.form = this.buildForm()
    }

    get valid(): boolean {
        if (this.form.untouched) return false
        return this.form.valid
    }

    getFormValue(): InputT {
        return this.form.value
    }

    setFormValue(dto: InputT | null): void {
        if (!dto) {
            this.form.reset()
            return
        }

        this.form.reset(dto)
        if (dto.id) {
            const control = new FormControl(dto.id)
            this.form.addControl('id', control)
        }
    }

    abstract buildForm(): FormGroup

    abstract loadFromApiAndFillForm$(id: string): Observable<T>

    save$(): Observable<T> {
        if (this.form.invalid) return throwError(() => new Error('Invalid form'))

        const id = this.form.get('id')?.value ?? null
        return id ? this.update$(id) : this.create$()
    }

    protected abstract create$(): Observable<T>

    protected abstract update$(id: string): Observable<T>
}

    

@Injectable()
export class MovieCreateFormService extends AbstractFormService<Movie, MovieCreateInput> {
    constructor(protected override fb: FormBuilder, private movieService: MovieService) {
        super(fb)
    }

    buildForm(): FormGroup {
        return this.fb.group({
            name: ['', Validators.required],
            releaseYear: '',
            genre: '',
        })
    }

    loadFromApiAndFillForm$(id: string): Observable<Movie> {
        return this.movieService
            .findById(id)
            .pipe(tap((data) => this.setFormValue(data)))
    }

    protected create$(): Observable<Movie> {
        return this.movieService
            .create(this.getFormValue())
            .pipe(tap(() => this.form.reset()))
    }

    protected update$(id: string): Observable<Movie> {
        return this.movieService
            .update(id, this.getFormValue())
            .pipe(tap(() => this.form.reset()))
    }
}

リンク:https ://javascript.plainenglish.io/a-better-way-to-use-angular-forms-cd22a5a0488a

#angular 

What is GEEK

Buddha Community

Angularフォームを使用するためのより良い方法

Angularフォームを使用するためのより良い方法

「大いなる力には、大いなる力には大いなる力があります」—あなたは誰を知っていますか。それは本当です!Angular Formsは強力であるだけでなく、コントローラーに大きな混乱を引き起こします。FormBuilder、FormGroup、FormControl、ロジックの保存、ロジックの更新—ほとんど狂気。今日は、フォームを管理し、正気をもたらす方法を紹介します。

サービスを入力してください—それらは注射可能であり、必要なときに提供されます。それなら、フォームを管理するためにサービスを使用してみませんか?それでは始めましょう。

最初のステップ:インターフェース

まず、インターフェースを作成する必要があります。このデモでActorは、2つのインターフェイスを作成します。これは最終的なエンティティでありActorCreateInput、フォーム入力の形状です。

2番目のステップ:サービス

ルートに挿入されない、つまり{ providedIn: 'root' }デコレータに渡されないActorCreateFormServiceを作成します。

これまでのところ、すべてが自明です。この段階では、サービスはFormGroupを作成し、それをformクラスプロパティに割り当てる以外は何もしません。フォームの値と有効性を取得するための便利なメソッドをいくつか追加しました。

アクターを保存または更新するには、HTTPサービスに接続する必要があります。その仕事をするActorApiServiceがあるとしましょう。だからそれを注入します:

constructor(
    private fb: FormBuilder,
    private actorApiService: ActorApiService,
) {}

次に、アクターを作成および更新するためのいくつかのメソッドを記述しましょう。

データベースからアクターをロードしてフォームに入力するには、最後の1つのメソッドが必要です。これは、アクターを編集する必要がある場合に便利です。

3番目のステップ:コントローラー

コンポーネントでどのように使用できるかを見てみましょう。で提供しなかったためroot、正しいスコープ(通常はコンポーネント)で提供する必要があります。

コントローラがどれほどきれいであるかに注目してください。さらに、他の場所でも同じフォームサービスを使用できます。

最終ステップ:抽象サービス

まだ終わっていません。よく見ると、フォームサービスには、他のフォームにも使用できる再利用可能な部分がいくつかあります。たとえば、MovieCreateFormServiceです。それでは、フォームクラスをさらに一歩進めて、抽象化してみましょうAbstractFormService。デコレータを含める必要がなくなりました@Injectable():(簡潔にするために一部のコードは省略されています)。

次に、MovieCreateFormServiceを作成して拡張します。

これで、フォームを実現するために4つのメソッドをオーバーライドする必要があります。フォームの送信時に、保存、更新、リセットを自動的に処理します。MovieCreateFormServiceこれで、以前と同じように使用できActorCreateFormServiceます。

最終的な考え

このアプローチについてどう思いますか?このパターンにより、アプリケーション全体で多くのLOC(コード行)が節約されると思います。しかし、潜在的な問題や改善についての考えを共有してください。

読んでくれてありがとう!

完全なコード

import { FormBuilder, FormControl, FormGroup } from '@angular/forms'
import { Observable, throwError } from 'rxjs'

export abstract class AbstractFormService<T, InputT extends { id?: string }> {
    form: FormGroup

    constructor(protected fb: FormBuilder) {
        this.form = this.buildForm()
    }

    get valid(): boolean {
        if (this.form.untouched) return false
        return this.form.valid
    }

    getFormValue(): InputT {
        return this.form.value
    }

    setFormValue(dto: InputT | null): void {
        if (!dto) {
            this.form.reset()
            return
        }

        this.form.reset(dto)
        if (dto.id) {
            const control = new FormControl(dto.id)
            this.form.addControl('id', control)
        }
    }

    abstract buildForm(): FormGroup

    abstract loadFromApiAndFillForm$(id: string): Observable<T>

    save$(): Observable<T> {
        if (this.form.invalid) return throwError(() => new Error('Invalid form'))

        const id = this.form.get('id')?.value ?? null
        return id ? this.update$(id) : this.create$()
    }

    protected abstract create$(): Observable<T>

    protected abstract update$(id: string): Observable<T>
}

    

@Injectable()
export class MovieCreateFormService extends AbstractFormService<Movie, MovieCreateInput> {
    constructor(protected override fb: FormBuilder, private movieService: MovieService) {
        super(fb)
    }

    buildForm(): FormGroup {
        return this.fb.group({
            name: ['', Validators.required],
            releaseYear: '',
            genre: '',
        })
    }

    loadFromApiAndFillForm$(id: string): Observable<Movie> {
        return this.movieService
            .findById(id)
            .pipe(tap((data) => this.setFormValue(data)))
    }

    protected create$(): Observable<Movie> {
        return this.movieService
            .create(this.getFormValue())
            .pipe(tap(() => this.form.reset()))
    }

    protected update$(id: string): Observable<Movie> {
        return this.movieService
            .update(id, this.getFormValue())
            .pipe(tap(() => this.form.reset()))
    }
}

リンク:https ://javascript.plainenglish.io/a-better-way-to-use-angular-forms-cd22a5a0488a

#angular