These are just ideas on implementing forms using ngrx tools. The whole idea is based on react-redux-forms
: http://redux-form.com/
@Component({
selector: `ngrx-forms-field`
template: ``
})
class NgrxFormsField {
constructor() {
// some magic here that uses the Field "component" input to fill the template
}
// these define the field
@Input() name: String;
@Input() component: Component | function | String;
@Input() validate: (value, allValues) => Error | undefined;
@Input() warn: (value, allValues) => Warning | undefined;
// field event
@Input() onBlur: () => void;
@Input() onChange: () => void;
@Input() onDragStart: (event: Event) => void;
@Input() onDrop: (event: Event) => void;
@Input() onFocus: (event: Event) => void;
@Input() value: string | boolean;
// field status
@Input() isActive: boolean
@Input() is autoFilled: boolean
@Input() isAsyncValidating: boolean
@Input() isDirty: boolean
@Input() error: Error;
@Input() warning: Warning;
@Input() isInvalid: boolean;
@Input() isValid: boolean;
@Input() isSubmitting: boolean;
}
@Component({
selector: 'ngrx-forms',
})
class NgrxForms {
constructor(private store: Store) {}
@Input() handleSubmit: (data: any) => void;
@Input() initialValues: any;
@Input() initialise: (data: any) => void;
@Input() validate: () => any;
@Input() asyncValidate: () => any;
@Input() warn: () => any;
// and lots of other inputs: see http://redux-form.com/6.4.3/docs/api/Props.md/
}
import { Action } from '@ngrx/store';
export class InitializeForm {
type = 'INITIALIZE_FORM'
constructor(payload: any) {}
// payload should be an object containing the form name and initial values plus some other stuff
}
export class TouchField {
type = 'TOUCH_FIELD'
constructor(payload: any) {}
// payload should be an object containing the form name and a list of fields to touch
}
export class SubmitForm {
type = 'SUBMIT_FORM'
constructor(payload: any) {}
// payload consists of form name
}
// and a whole lot of other actions
export function NgrxFormsReducer(state: NgrxFormsStore = initialNgrxFormsState,
action: Action) {
// handle all actions here
}
By seeing how the reducers are implemented, it can be seen what is saved in the state. Everything is stored!, here are the important things:
store = {
otherState: {},
forms: {
simpleForm: {
fields: {
firstName: { touched: true, autofilled: false, visisted: true, active: false},
}
initial: { firstName: 'Smith' },
values: { firstName: 'Smith' },
asyncErrors: {},
syncErrors: {}
submitErrors: { firstName: '' },
anyTouched: true,
submitting: false,
}
}
}
Let's see how a simple form can be made:
@Component({
selector: 'simple-form',
template: `
<form #f (submit)="handleSubmit(#f)">
<ngrx-forms-field name="firstName" component="firstNameField" label="First Name">
</ngrx-forms-field>
</form>
`
})
class SimpleForm extends NgrxForms{
constructor() {}
}
@Component({
selector: 'smart-component',
template: `<simple-form [handleSubmit]="doWhatever" [initialValues]="initialData"></simple-form>`
})
class SmartComponent {
constructor() {}
doWhatever() {
}
// initialData = ...
}
Now what remains in this psuedo-code is connecting the SimpleForm
to the Store
. Redux-Forms uses a decorator called reduxForm()
(http://redux-form.com/6.4.3/docs/api/ReduxForm.md/) which the form component (the dumb component) is given as its arguments. This decorator does all the magic of storing the form state in the store. This includes dispatching actions and so on. This can be found here https://github.com/erikras/redux-form/blob/master/src/reduxForm.js . I don't fully understand it as there is too much react
in it which I do not know much about.