2016-07-29 20 views
32

Jak obsługiwać formularze Angular 2 w jednokierunkowym przepływie danych? Szczególnie w przypadku sprawdzania poprawności między kilkoma komponentami nadrzędnymi/podrzędnymi?Angular 2 + ngrx (redux) + formularze

Używam formularzy ngrx/store i modelowania z narzędziem do tworzenia formularzy. Czy w React można zrobić coś podobnego, jak reduktor formularzy i uczynić go częścią Sklepu?

Czy masz jakieś artykuły na ten temat?

+2

Używam ngrx, ale nie robię sprawdzania formularza jako takiego. Postanowiłem zostawić NgModel, aby wykonać swoją działalność (mutując ...) bez przeszkód. Używam przycisku przesyłania do wysyłania danych do sklepu i wyzwalania zmian w pozostałej części aplikacji. –

+1

Można użyć sklepu w połączeniu z formularzami opartymi na modelach. Sprawdź ten świetny artykuł na ten temat: http://blog.thoughtram.io/angular/2016/06/22/model-driven-forms-in-angular-2.html –

+0

Poszukuję też miłego przykładu, istnieje mnóstwo tutoriali i blogów na temat formularzy i ngrx, ale nie razem. – Seb

Odpowiedz

4

W aplikacjach I zbudowanych z Kątowymi 2, następujące wytyczne wydawało się działać dobrze:

komponenty rodzicielskie przekazać dane do dzieci poprzez wiązanie danych. Komponenty potomne żądają zmian danych, emitując zdarzenia wyjściowe do komponentów nadrzędnych. Do obowiązków rodzica należy podjęcie odpowiednich działań.

W hierarchicznej strukturze komponentów zmiany danych są obsługiwane przez najniższy komponent, który zależy od danych. Jeśli istnieje inny komponent wyżej lub rodzeństwo, które zależy od tego samego elementu danych, przekazuj zmiany przez emitowanie zdarzeń i pozostaw przetwarzanie do wyższego komponentu.

Ten schemat działa dobrze, ponieważ w przypadku danych związanych z więcej niż jednym komponentem istnieje pojedynczy składnik odpowiedzialny za wprowadzanie zmian. Zmienia się bańka automatycznie. Komponenty są wielokrotnego użytku, a zmiany w drzewie komponentów można łatwo dostosować.

W odniesieniu do sprawdzania poprawności, każdy element drabiny między najniższym komponentem wysyłającym żądanie zmiany danych, a najwyższym komponentem, który ostatecznie obsługuje zmianę, każdy składnik może skutecznie anulować zmianę, nie przekazując jej wyżej. W większości aplikacji wolałbym zatwierdzać zmiany danych w miejscu pochodzenia zmiany.

Oczywiście komponenty potomne mogą nadal mieć stan wewnętrzny i nie muszą komunikować zmian - chyba że zmiany dotyczą elementu nadrzędnego.

3

Dane formularzy są z natury bardzo lokalnym stanem, szczególnie w przypadku Angular, ponieważ ngModel wiąże się z lokalnymi zmiennymi składowymi. Najlepsi twórcy, których znam, zalecają przechowywanie danych dla formularza zlokalizowanego w tym komponencie (tj. Po prostu użyj ngModel ze zmiennymi lokalnymi). Dzieje się tak, ponieważ nieprzesłane dane formularzy prawie nigdy nie są udostępniane przez różne komponenty w całej aplikacji. Kiedy użytkownik przesyła formularz, możesz wysłać akcję z ładunkiem zawierającym dane formularza do komponentu nadrzędnego, do sklepu lub nawet do ngrx/effect, który zostanie wysłany na serwer.

+1

Tak? Zlokalizowany? Spójrz na Wiąz - wszystkie części aplikacji powinny być w kształcie stanu. –

+0

Współdzielenie danych między komponentami to tylko jedna z zalet pojedynczego magazynu stanów. To nie może być pełna odpowiedź. –

+0

@YuriyYakovenko Nie jest konieczne zapisywanie rzeczy istotnych tylko w jednym zdalnym rogu aplikacji w stanie poziomu aplikacji. To nie był questino o Wiązzie. Było to pytanie dotyczące Angular 2, a sposób, w jaki Angular 2 obsługuje formularze, prawie musisz związać z rzeczami w kontrolerze - tj. Lokalnym stanie. – Jim

5

To dość stare pytanie, ale nie mogłem znaleźć dobrego rozwiązania w mojej własnej misji pracy z formami ngrx + reaktywnymi w Angular. W rezultacie opublikuję tutaj moje badania z nadzieją, że może to pomóc komuś innemu. Moje rozwiązanie można podzielić na dwie części i modlę się (o zwietrzałą duszę), aby znalazło zastosowanie w twoim problemie:

1) Monitoruj element formularza/s (na przykład zdarzenie "keyup" dla typowego tekstu wejście) i zaktualizować stan z tego zdarzenia. Ta strategia pochodzi prosto z book search component z ngrx example app. Możemy teraz z powodzeniem zaludnić państwo w miarę zmiany formy. Niesamowite! 50% gotów!

2) Kątowy reactive forms guide demonstruje utworzenie grupy formularzy w konstruktorze. Widziałem, jak inni ludzie robili to wewnątrz NgOnInit, ale jest to za późno w cyklu życia dla naszych potrzeb (próbowałem, nie udało mi się). Po utworzeniu naszej grupy formularzy skonfiguruj ngOnChanges w celu przechwycenia wszelkich zmian wypychanych ze stanu, a następnie zaktualizuj grupę formularzy za pomocą patchValue.Na przykład:

ngOnChanges(changes: SimpleChanges) { 
    if (changes.valueICareAbout1) { 
     this.myForm.patchValue({ 
     valueICareAbout1: changes.valueICareAbout1.currentValue 
     }); 
    } 
    if (changes.valueICareAbout2) { 
     this.myForm.patchValue({ 
     valueICareAbout2: changes.valueICareAbout2.currentValue 
     }); 
    } 
    } 
+0

To było pomocne, dzięki! – John

8

stworzyłem bibliotekę nazywa ngrx-forms że robi dokładnie to, co chcesz. Można go pobrać na KMP poprzez:

npm install ngrx-forms --save 

I polecam sprawdzić pełną README na stronie github, ale poniżej znajdziesz kilka przykładów tego, co trzeba zrobić, aby dostać się do góry biblioteki i działa po zainstalowaniu.

importu moduł:

import { StoreModule } from '@ngrx/store'; 
import { NgrxFormsModule } from 'ngrx-forms'; 

import { reducers } from './reducer'; 

@NgModule({ 
    declarations: [ 
    AppComponent, 
    ], 
    imports: [ 
    NgrxFormsModule, 
    StoreModule.forRoot(reducers), 
    ], 
    providers: [], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

Dodaj stan grupy gdzieś w drzewie państwowej poprzez createFormGroupState i wywołać formGroupReducer wewnątrz reduktora:

import { Action } from '@ngrx/store'; 
import { FormGroupState, createFormGroupState, formGroupReducer } from 'ngrx-forms'; 

export interface MyFormValue { 
    someTextInput: string; 
    someCheckbox: boolean; 
    nested: { 
    someNumber: number; 
    }; 
} 

const FORM_ID = 'some globally unique string'; 

const initialFormState = createFormGroupState<MyFormValue>(FORM_ID, { 
    someTextInput: '', 
    someCheckbox: false, 
    nested: { 
    someNumber: 0, 
    }, 
}); 

export interface AppState { 
    someOtherField: string; 
    myForm: FormGroupState<MyFormValue>; 
} 

const initialState: AppState = { 
    someOtherField: '', 
    myForm: initialFormState, 
}; 

export function appReducer(state = initialState, action: Action): AppState { 
    const myForm = formGroupReducer(state.myForm, action); 
    if (myForm !== state.myForm) { 
    state = { ...state, myForm }; 
    } 

    switch (action.type) { 
    case 'some action type': 
     // modify state 
     return state; 

    default: { 
     return state; 
    } 
    } 
} 

Expose stan formularz wewnątrz komponentu:

import { Component } from '@angular/core'; 
import { Store } from '@ngrx/store'; 
import { FormGroupState } from 'ngrx-forms'; 
import { Observable } from 'rxjs/Observable'; 

import { MyFormValue } from './reducer'; 

@Component({ 
    selector: 'my-component', 
    templateUrl: './my-component.html', 
}) 
export class MyComponent { 
    formState$: Observable<FormGroupState<MyFormValue>>; 

    constructor(private store: Store<AppState>) { 
    this.formState$ = store.select(s => s.myForm); 
    } 
} 

Ustaw kontr stany oli w twoim szablonie:

<form novalidate [ngrxFormState]="(formState$ | async)"> 
    <input type="text" 
     [ngrxFormControlState]="(formState$ | async).controls.someTextInput"> 

    <input type="checkbox" 
     [ngrxFormControlState]="(formState$ | async).controls.someCheckbox"> 

    <input type="number" 
     [ngrxFormControlState]="(formState$ | async).controls.nested.controls.someNumber"> 
</form> 
+0

Chciałem tylko powiedzieć ... Uwielbiam tę bibliotekę - dziękuję za udostępnienie! – Drammy