5

Currently I have a project that uses NGRX for its store and reactive forms.

In my application, I want to map the active item in my state to the reactive forms. So in my component I have something like:

export class MyComponent {

    active$: Observable<any>;

    form = this.fb.group({
        name: ['', [Validators.required]],
        description: ['', Validators.maxLength(256)]
    });

    constructor(private fb: FormBuilder, private store: Store<any>) {
        this.active$ = store.select(store => store.items);
    }
    
}

In order to avoid having to subscribe to the store and select out my items, I created a directive to bind my observable to my form:

import { Directive, Input } from '@angular/core';
import { FormGroupDirective } from '@angular/forms';

@Directive({
    selector: '[connectForm]'
})
export class ConnectFormDirective {

    @Input('connectForm')
    set data(val: any) {
        if (val) {
            this.formGroupDirective.form.patchValue(val);
            this.formGroupDirective.form.markAsPristine();
        }
    }

    constructor(private formGroupDirective: FormGroupDirective) { }

}

Now in my form I simply bind it like so:

<form [formGroup]="form" novalidate (ngSubmit)="onSubmit()" [connectForm]="active$ | async">
</form>

My question is:

  • Is this a good idea / is there a better way to handle this?

I suppose at the end of the day for complicated scenarios you are going to have to end up subscribing to the observable in the component.

2 Answers 2

8

You should consider splitting your components into the "Connected" and "Presentation" components. Your connected component will be responsible for querying the store and emitting actions to the store, where your presentation component will create a form group and accept values from the store as @Input parameters. You can then listen for value changes in the form group in the presentation component and raise events with updated values to the connected component. Connected component will then handle the event from presentation component and raise a new action to update values in the store.

Sign up to request clarification or add additional context in comments.

Comments

0

No, this seems like a bad practice to me. Forms should be their own component used within a parent view component. You can then pass it data with the @Input decorator if it's supposed to be for edition.

So in your parent component you would do something like this:

<form-component [data]="active$ | async"></form-component>

And in the form component you can do this:

ngOnInit{
    if(this.data)
        this.form.patchValue(this.data)
}

To disable a form control with ReactiveForms, you use the disable method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.