Skip to content

Commit

Permalink
Fields added for and selectors (redux-form#3900)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriusBil authored and erikras committed Mar 23, 2018
1 parent 9cb8816 commit 2748654
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 33 deletions.
54 changes: 26 additions & 28 deletions docs/api/Selectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,24 @@ import {
hasSubmitFailed
} from 'redux-form'

MyComponent = connect(
state => ({
values: getFormValues('myForm')(state),
initialValues: getFormInitialValues('myForm')(state),
formSyncErrors: getFormSyncErrors('myForm')(state),
fields: getFormMeta('myForm')(state),
formAsyncErrors: getFormAsyncErrors('myForm')(state),
syncWarnings: getFormSyncWarnings('myForm')(state),
submitErrors: getFormSubmitErrors('myForm')(state),
formError: getFormError()(state),
names: getFormNames()(state),
dirty: isDirty('myForm')(state),
pristine: isPristine('myForm')(state),
valid: isValid('myForm')(state),
invalid: isInvalid('myForm')(state),
submitting: isSubmitting('myForm')(state),
submitSucceeded: hasSubmitSucceeded('myForm')(state),
submitFailed: hasSubmitFailed('myForm')(state)
})
)(MyComponent)
MyComponent = connect(state => ({
values: getFormValues('myForm')(state),
initialValues: getFormInitialValues('myForm')(state),
formSyncErrors: getFormSyncErrors('myForm')(state),
fields: getFormMeta('myForm')(state),
formAsyncErrors: getFormAsyncErrors('myForm')(state),
syncWarnings: getFormSyncWarnings('myForm')(state),
submitErrors: getFormSubmitErrors('myForm')(state),
formError: getFormError()(state),
names: getFormNames()(state),
dirty: isDirty('myForm')(state),
pristine: isPristine('myForm')(state),
valid: isValid('myForm')(state),
invalid: isInvalid('myForm')(state),
submitting: isSubmitting('myForm')(state),
submitSucceeded: hasSubmitSucceeded('myForm')(state),
submitFailed: hasSubmitFailed('myForm')(state)
}))(MyComponent)
```

## List of Selectors
Expand Down Expand Up @@ -97,30 +95,30 @@ MyComponent = connect(
> The reason that this is a function that returns a function is twofold:
> 1. symmetry with the other selectors
> 2. to allow for the `getFormState` parameter described at the top of this page.
> 1. symmetry with the other selectors
> 2. to allow for the `getFormState` parameter described at the top of this page.
> If you are using ImmutableJS, it will return a `List`.
### `isDirty(formName:String)` returns `(state) => dirty:boolean`
### `isDirty(formName:String)` returns `(state, ...fields:String[]) => dirty:boolean`

> Returns `true` if the form is dirty, i.e. the values have been altered from the original
`initialValues` provided. The opposite of `isPristine`.
> `initialValues` provided. The opposite of `isPristine`.
### `isPristine(formName:String)` returns `(state) => pristine:boolean`
### `isPristine(formName:String)` returns `(state, ...fields:String[]) => pristine:boolean`

> Returns `true` if the form is pristine, i.e. the values have NOT been altered from the original
`initialValues` provided. The opposite of `isDirty`.
> `initialValues` provided. The opposite of `isDirty`.
### `isValid(formName:String)` returns `(state) => valid:boolean`

> Returns `true` if the form is valid, i.e. has no sync, async, or submission errors. The opposite
of `isInvalid`.
> of `isInvalid`.
### `isInvalid(formName:String)` returns `(state) => invalid:boolean`

> Returns `true` if the form is invalid, i.e. has sync, async, or submission errors. The opposite
of `isValid`.
> of `isValid`.
### `isSubmitting(formName:String)` returns `(state) => submitting:boolean`

Expand Down
45 changes: 45 additions & 0 deletions src/selectors/__tests__/isDirty.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,51 @@ const describeIsDirty = (name, structure, setup) => {
)
).toBe(true)
})

it('should return false if specified fields pristine', () => {
expect(
isDirty('foo')(
fromJS({
form: {
foo: {
initial: {
dog: 'Snoopy',
cat: 'Garfield'
},
values: {
dog: 'Odie',
cat: 'Garfield'
}
}
}
}),
'cat'
)
).toBe(false)
})

it('should return true if specified fields dirty', () => {
expect(
isDirty('foo')(
fromJS({
form: {
foo: {
initial: {
dog: 'Snoopy',
cat: 'Garfield'
},
values: {
dog: 'Odie',
cat: 'Garfield'
}
}
}
}),
'cat',
'dog'
)
).toBe(true)
})
})
}

Expand Down
47 changes: 46 additions & 1 deletion src/selectors/__tests__/isPristine.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const describeIsPristine = (name, structure, setup) => {
).toBe(true)
})

it('should return true when values are dirty', () => {
it('should return false when values are dirty', () => {
expect(
isPristine('foo')(
fromJS({
Expand Down Expand Up @@ -90,6 +90,51 @@ const describeIsPristine = (name, structure, setup) => {
)
).toBe(false)
})

it('should return true if specified fields pristine', () => {
expect(
isPristine('foo')(
fromJS({
form: {
foo: {
initial: {
dog: 'Snoopy',
cat: 'Garfield'
},
values: {
dog: 'Odie',
cat: 'Garfield'
}
}
}
}),
'cat'
)
).toBe(true)
})

it('should return false if specified fields dirty', () => {
expect(
isPristine('foo')(
fromJS({
form: {
foo: {
initial: {
dog: 'Snoopy',
cat: 'Garfield'
},
values: {
dog: 'Odie',
cat: 'Garfield'
}
}
}
}),
'cat',
'dog'
)
).toBe(false)
})
})
}

Expand Down
2 changes: 1 addition & 1 deletion src/selectors/isDirty.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const createIsDirty = (structure: Structure<*, *>) => (
getFormState: ?GetFormState
): IsDirtyInterface => {
const isPristine = createIsPristine(structure)(form, getFormState)
return (state: any) => !isPristine(state)
return (state: any, ...fields: string[]) => !isPristine(state, ...fields)
}

export default createIsDirty
2 changes: 1 addition & 1 deletion src/selectors/isDirty.types.js.flow
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// @flow
export type IsDirtyInterface = (state: any) => boolean
export type IsDirtyInterface = (state: any, ...fields?: string[]) => boolean
9 changes: 8 additions & 1 deletion src/selectors/isPristine.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ import type { IsPristineInterface } from './isPristine.types'
const createIsPristine = ({ deepEqual, empty, getIn }: Structure<*, *>) => (
form: string,
getFormState: ?GetFormState
): IsPristineInterface => (state: any) => {
): IsPristineInterface => (state: any, ...fields: string[]) => {
const nonNullGetFormState: GetFormState =
getFormState || (state => getIn(state, 'form'))
const formState = nonNullGetFormState(state)
if (fields && fields.length) {
return fields.every(field => {
const fieldInitial = getIn(formState, `${form}.initial.${field}`)
const fieldValue = getIn(formState, `${form}.values.${field}`)
return deepEqual(fieldInitial, fieldValue)
})
}
const initial = getIn(formState, `${form}.initial`) || empty
const values = getIn(formState, `${form}.values`) || initial
return deepEqual(initial, values)
Expand Down
2 changes: 1 addition & 1 deletion src/selectors/isPristine.types.js.flow
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// @flow
export type IsPristineInterface = (state: any) => boolean
export type IsPristineInterface = (state: any, ...fields?: string[]) => boolean

0 comments on commit 2748654

Please sign in to comment.