separate field array props as voted on #1063

This commit is contained in:
Erik Rasmussen
2016-05-30 19:59:47 +02:00
parent a43233e365
commit 15fb5c4279
7 changed files with 179 additions and 202 deletions

View File

@@ -52,71 +52,73 @@ The following properties and methods are available on an instance of a `FieldArr
## Props
These are props that `FieldArray` will pass to your wrapped component.
These are props that `FieldArray` will pass to your wrapped component. As you can see, they are
all under the `fields` key. Any additional props that you pass to `FieldArray` will be passed
along, but will _not_ be under the `fields` key.
#### `dirty : boolean`
#### `fields.dirty : boolean`
> `true` if the any of the fields in the field array have changed from their initialized value.
Opposite of `pristine`.
#### `error : String` [optional]
#### `fields.error : String` [optional]
> The error for this field array if its value is not passing validation. Both synchronous,
asynchronous, and submit validation errors will be reported here. Array-specific errors should be
returned from the validation function as an `_error` key on the array.
#### `forEach(callback) : Function`
#### `fields.forEach(callback) : Function`
> A method to iterate over each value of the array. See the section on [Iteration](#iteration)
for more details.
#### `insert(index, value) : Function`
#### `fields.insert(index, value) : Function`
> A function to insert a new value into the array at any arbitrary index.
#### `invalid : boolean`
#### `fields.invalid : boolean`
> `true` if the field array value fails validation (has a validation error). Opposite of `valid`.
#### `length : Number`
#### `fields.length : Number`
> The current length of the array.
#### `map(callback) : Function`
#### `fields.map(callback) : Function`
> A method to iterate over each value of the array. Returns an array of the results of each call
to the callback. See the section on [Iteration](#iteration) for more details.
#### `pop() : Function`
#### `fields.pop() : Function`
> Removes an item from the end of the array. Returns the item removed.
#### `pristine : boolean`
#### `fields.pristine : boolean`
> `true` if the all of the fields in the field array are the same as their initialized
value. Opposite of `dirty`.
#### `push(value) : Function`
#### `fields.push(value) : Function`
> Adds a value to the end of the array. Returns nothing.
#### `remove(index) : Function`
#### `fields.remove(index) : Function`
> Removes an item from the array at an arbitrary index. Returns nothing.
#### `shift() : Function`
#### `fields.shift() : Function`
> Removes an item from beginning of the array. Returns the item removed..
#### `swap(indexA, indexB) : Function`
#### `fields.swap(indexA, indexB) : Function`
> Swaps two items in the array at the given indexes. Returns nothing.
#### `unshift(value) : Function`
#### `fields.unshift(value) : Function`
> Adds an item to the beginning of the array. Returns nothing.
#### `valid : boolean`
#### `fields.valid : boolean`
> `true` if the field value passes validation (has no validation errors). Opposite of `invalid`.

View File

@@ -12,18 +12,18 @@ const renderField = props => (
</div>
)
const renderMembers = members => (
const renderMembers = ({ fields }) => (
<ul>
<li>
<button type="button" onClick={() => members.push({})}>Add Member</button>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
</li>
{members.map((member, memberIndex) =>
<li key={memberIndex}>
{fields.map((member, index) =>
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => members.remove(memberIndex)}/>
<h4>Member #{memberIndex + 1}</h4>
onClick={() => fields.remove(index)}/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
@@ -40,25 +40,25 @@ const renderMembers = members => (
</ul>
)
const renderHobbies = hobbies => (
const renderHobbies = ({ fields }) => (
<ul>
<li>
<button type="button" onClick={() => hobbies.push()}>Add Hobby</button>
<button type="button" onClick={() => fields.push()}>Add Hobby</button>
</li>
{hobbies.map((hobby, hobbyIndex) =>
<li key={hobbyIndex}>
{fields.map((hobby, index) =>
<li key={index}>
<button
type="button"
title="Remove Hobby"
onClick={() => hobbies.remove(hobbyIndex)}/>
onClick={() => fields.remove(index)}/>
<Field
name={hobby}
type="text"
component={renderField}
placeholder={`Hobby #${hobbyIndex + 1}`}/>
placeholder={`Hobby #${index + 1}`}/>
</li>
)}
{hobbies.error && <li className="error">{hobbies.error}</li>}
{fields.error && <li className="error">{fields.error}</li>}
</ul>
)

View File

@@ -46,7 +46,6 @@ const createConnectedField = ({
render() {
const { component, defaultValue, withRef, ...rest } = this.props
const { _reduxForm: { adapter } } = this.context
const props = createFieldProps(getIn,
name,
rest,
@@ -57,14 +56,7 @@ const createConnectedField = ({
if (withRef) {
props.ref = 'renderedComponent'
}
let element
if (adapter) {
element = adapter(component, props)
}
if (!element) {
element = createElement(component, props)
}
return element
return createElement(component, props)
}
}

View File

@@ -454,59 +454,6 @@ const describeField = (name, structure, combineReducers, expect) => {
expect(input.calls[ 1 ].arguments[ 0 ].bar).toBe('baz')
})
it('should use adapter to render fields', () => {
const store = makeStore({
testForm: {
values: {
cow: 'calf',
horse: 'foal',
sheep: 'lamb',
donkey: 'foal',
chicken: 'chick'
}
}
})
const adapter = createSpy(props => <div {...props}/>).andCallThrough()
class Form extends Component {
render() {
return (<div>
<Field name="cow" component="Cow" says="moo"/>
<Field name="horse" component="Horse" says="neigh"/>
<Field name="sheep" component="Sheep" says="baa"/>
<Field name="donkey" component="Donkey" says="heehaw"/>
<Field name="chicken" component="Chicken" says="cluck"/>
</div>)
}
}
const TestForm = reduxForm({
form: 'testForm',
adapter
})(Form)
TestUtils.renderIntoDocument(
<Provider store={store}>
<TestForm/>
</Provider>
)
expect(adapter).toHaveBeenCalled()
expect(adapter.calls.length).toBe(5)
expect(adapter.calls[ 0 ].arguments[ 0 ]).toBe('Cow')
expect(adapter.calls[ 0 ].arguments[ 1 ].says).toBe('moo')
expect(adapter.calls[ 0 ].arguments[ 1 ].value).toBe('calf')
expect(adapter.calls[ 1 ].arguments[ 0 ]).toBe('Horse')
expect(adapter.calls[ 1 ].arguments[ 1 ].says).toBe('neigh')
expect(adapter.calls[ 1 ].arguments[ 1 ].value).toBe('foal')
expect(adapter.calls[ 2 ].arguments[ 0 ]).toBe('Sheep')
expect(adapter.calls[ 2 ].arguments[ 1 ].says).toBe('baa')
expect(adapter.calls[ 2 ].arguments[ 1 ].value).toBe('lamb')
expect(adapter.calls[ 3 ].arguments[ 0 ]).toBe('Donkey')
expect(adapter.calls[ 3 ].arguments[ 1 ].says).toBe('heehaw')
expect(adapter.calls[ 3 ].arguments[ 1 ].value).toBe('foal')
expect(adapter.calls[ 4 ].arguments[ 0 ]).toBe('Chicken')
expect(adapter.calls[ 4 ].arguments[ 1 ].says).toBe('cluck')
expect(adapter.calls[ 4 ].arguments[ 1 ].value).toBe('chick')
})
// ----------------------------------------------
// Uncomment this to confirm that #1024 is fixed.
// ----------------------------------------------

View File

@@ -66,7 +66,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
foo: [ 'a', 'b', 'c' ]
}
})
expect(props.length).toBe(3)
expect(props.fields.length).toBe(3)
})
it('should be okay with no array value', () => {
@@ -74,9 +74,9 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
const props = testProps({
values: {}
})
expect(props.length).toBe(0)
props.forEach(iterate)
props.map(iterate)
expect(props.fields.length).toBe(0)
props.fields.forEach(iterate)
props.fields.map(iterate)
expect(iterate).toNotHaveBeenCalled()
})
@@ -89,8 +89,8 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
foo: [ 'a', 'b', 'c' ]
}
})
expect(props1.pristine).toBe(true)
expect(props1.dirty).toBe(false)
expect(props1.fields.pristine).toBe(true)
expect(props1.fields.dirty).toBe(false)
const props2 = testProps({
initial: {
foo: [ 'a', 'b', 'c' ]
@@ -99,15 +99,49 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
foo: [ 'a', 'b' ]
}
})
expect(props2.pristine).toBe(false)
expect(props2.dirty).toBe(true)
expect(props2.fields.pristine).toBe(false)
expect(props2.fields.dirty).toBe(true)
})
it('should provide pass through other props', () => {
const store = makeStore({
testForm: {
values: {
foo: [ 'bar' ]
}
}
})
const renderArray = createSpy(() => <div/>).andCallThrough()
class Form extends Component {
render() {
return <div>
<FieldArray
name="foo"
component={renderArray}
otherProp="dog"
anotherProp="cat"
/>
</div>
}
}
const TestForm = reduxForm({ form: 'testForm' })(Form)
TestUtils.renderIntoDocument(
<Provider store={store}>
<TestForm/>
</Provider>
)
expect(renderArray).toHaveBeenCalled()
expect(renderArray.calls.length).toBe(1)
expect(renderArray.calls[0].arguments[0].fields.length).toBe(1)
expect(renderArray.calls[0].arguments[0].otherProp).toBe('dog')
expect(renderArray.calls[0].arguments[0].anotherProp).toBe('cat')
})
it('should provide access to rendered component', () => {
const store = makeStore({
testForm: {
values: {
foo: 'bar'
foo: [ 'bar' ]
}
}
})
@@ -139,9 +173,9 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
foo: [ 'a', 'b', 'c' ]
}
})
expect(props.length).toBe(3)
expect(props.fields.length).toBe(3)
const iterate = createSpy()
props.forEach(iterate)
props.fields.forEach(iterate)
expect(iterate).toHaveBeenCalled()
expect(iterate.calls.length).toBe(3)
expect(iterate.calls[ 0 ].arguments[ 0 ]).toBe('foo[0]')
@@ -157,7 +191,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
}, {
validate: () => ({ foo: { _error: 'foo error' } })
})
expect(props.error).toBe('foo error')
expect(props.fields.error).toBe('foo error')
})
it('should get async errors from Redux state', () => {
@@ -171,7 +205,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
}
}
})
expect(props.error).toBe('foo error')
expect(props.fields.error).toBe('foo error')
})
it('should get submit errors from Redux state', () => {
@@ -185,7 +219,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
}
}
})
expect(props.error).toBe('foo error')
expect(props.fields.error).toBe('foo error')
})
it('should provide name getter', () => {
@@ -210,7 +244,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
const stub = TestUtils.findRenderedComponentWithType(dom, FieldArray)
expect(stub.name).toEqual('foo')
})
it('should provide value getter', () => {
const store = makeStore({
testForm: {
@@ -358,21 +392,21 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
}
]
})
const renderArray = ({ fields }) =>
<div>
{fields.map((name, index) =>
<div key={index}>
<Field name={`${name}.library`} component="input"/>
<Field name={`${name}.author`} component="input"/>
<Field name={name} component={props => <strong>{props.error}</strong>}/>
</div>
)}
</div>
class Form extends Component {
render() {
return (
<div>
<FieldArray name="foo" component={array =>
<div>
{array.map((name, index) =>
<div key={index}>
<Field name={`${name}.library`} component="input"/>
<Field name={`${name}.author`} component="input"/>
<Field name={name} component={props => <strong>{props.error}</strong>}/>
</div>
)}
</div>
}/>
<FieldArray name="foo" component={renderArray}/>
</div>
)
}
@@ -401,7 +435,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
}
}
})
const input = createSpy(() => <div/>).andCallThrough()
const component = createSpy(() => <div/>).andCallThrough()
class Form extends Component {
constructor() {
super()
@@ -410,7 +444,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
render() {
return (<div>
<FieldArray name={this.state.field} component={input}/>
<FieldArray name={this.state.field} component={component}/>
<button onClick={() => this.setState({ field: 'bar' })}>Change</button>
</div>)
}
@@ -421,20 +455,20 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
<TestForm/>
</Provider>
)
expect(input).toHaveBeenCalled()
expect(input.calls.length).toBe(1)
expect(input.calls[ 0 ].arguments[ 0 ].length).toBe(2)
expect(component).toHaveBeenCalled()
expect(component.calls.length).toBe(1)
expect(component.calls[ 0 ].arguments[ 0 ].fields.length).toBe(2)
const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
TestUtils.Simulate.click(button)
expect(input.calls.length).toBe(2)
expect(input.calls[ 1 ].arguments[ 0 ].length).toBe(1)
expect(component.calls.length).toBe(2)
expect(component.calls[ 1 ].arguments[ 0 ].fields.length).toBe(1)
})
it('should reconnect when props change', () => {
const store = makeStore()
const input = createSpy(() => <div/>).andCallThrough()
const component = createSpy(() => <div/>).andCallThrough()
class Form extends Component {
constructor() {
super()
@@ -443,7 +477,7 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
render() {
return (<div>
<FieldArray name="foo" foo={this.state.foo} bar={this.state.bar} component={input}/>
<FieldArray name="foo" foo={this.state.foo} bar={this.state.bar} component={component}/>
<button onClick={() => this.setState({ foo: 'qux', bar: 'baz' })}>Change</button>
</div>)
}
@@ -454,17 +488,17 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
<TestForm/>
</Provider>
)
expect(input).toHaveBeenCalled()
expect(input.calls.length).toBe(1)
expect(input.calls[ 0 ].arguments[ 0 ].foo).toBe('foo')
expect(input.calls[ 0 ].arguments[ 0 ].bar).toBe('bar')
expect(component).toHaveBeenCalled()
expect(component.calls.length).toBe(1)
expect(component.calls[ 0 ].arguments[ 0 ].foo).toBe('foo')
expect(component.calls[ 0 ].arguments[ 0 ].bar).toBe('bar')
const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
TestUtils.Simulate.click(button)
expect(input.calls.length).toBe(2)
expect(input.calls[ 1 ].arguments[ 0 ].foo).toBe('qux')
expect(input.calls[ 1 ].arguments[ 0 ].bar).toBe('baz')
expect(component.calls.length).toBe(2)
expect(component.calls[ 1 ].arguments[ 0 ].foo).toBe('qux')
expect(component.calls[ 1 ].arguments[ 0 ].bar).toBe('baz')
})
it('should rerender when array sync error appears or disappears', () => {
@@ -476,10 +510,10 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
}
})
const renderFieldArray =
createSpy(dogs => (<div>
{dogs.map((dog, index) => <input key={index} {...dog}/>)}
<button className="add" onClick={() => dogs.push()}>Add Dog</button>
<button className="remove" onClick={() => dogs.pop()}>Remove Dog</button>
createSpy(({ fields }) => (<div>
{fields.map((field, index) => <input key={index} {...field}/>)}
<button className="add" onClick={() => fields.push()}>Add Dog</button>
<button className="remove" onClick={() => fields.pop()}>Remove Dog</button>
</div>)).andCallThrough()
class Form extends Component {
render() {
@@ -513,36 +547,36 @@ const describeFieldArray = (name, structure, combineReducers, expect) => {
// length is 0, ERROR!
expect(renderFieldArray).toHaveBeenCalled()
expect(renderFieldArray.calls.length).toBe(1)
expect(renderFieldArray.calls[ 0 ].arguments[ 0 ].length).toBe(0)
expect(renderFieldArray.calls[ 0 ].arguments[ 0 ].error)
expect(renderFieldArray.calls[ 0 ].arguments[ 0 ].fields.length).toBe(0)
expect(renderFieldArray.calls[ 0 ].arguments[ 0 ].fields.error)
.toExist()
.toBe('No dogs')
TestUtils.Simulate.click(addButton) // length goes to 1, no error yet
expect(renderFieldArray.calls.length).toBe(2)
expect(renderFieldArray.calls[ 1 ].arguments[ 0 ].length).toBe(1)
expect(renderFieldArray.calls[ 1 ].arguments[ 0 ].error).toNotExist()
expect(renderFieldArray.calls[ 1 ].arguments[ 0 ].fields.length).toBe(1)
expect(renderFieldArray.calls[ 1 ].arguments[ 0 ].fields.error).toNotExist()
TestUtils.Simulate.click(addButton) // length goes to 2, ERROR!
expect(renderFieldArray.calls.length).toBe(3)
expect(renderFieldArray.calls[ 2 ].arguments[ 0 ].length).toBe(2)
expect(renderFieldArray.calls[ 2 ].arguments[ 0 ].error)
expect(renderFieldArray.calls[ 2 ].arguments[ 0 ].fields.length).toBe(2)
expect(renderFieldArray.calls[ 2 ].arguments[ 0 ].fields.error)
.toExist()
.toBe('Too many')
TestUtils.Simulate.click(removeButton) // length goes to 1, ERROR disappears!
expect(renderFieldArray.calls.length).toBe(4)
expect(renderFieldArray.calls[ 3 ].arguments[ 0 ].length).toBe(1)
expect(renderFieldArray.calls[ 3 ].arguments[ 0 ].error).toNotExist()
expect(renderFieldArray.calls[ 3 ].arguments[ 0 ].fields.length).toBe(1)
expect(renderFieldArray.calls[ 3 ].arguments[ 0 ].fields.error).toNotExist()
TestUtils.Simulate.click(removeButton) // length goes to 0, ERROR!
expect(renderFieldArray.calls.length).toBe(5)
expect(renderFieldArray.calls[ 4 ].arguments[ 0 ].length).toBe(0)
expect(renderFieldArray.calls[ 4 ].arguments[ 0 ].error)
expect(renderFieldArray.calls[ 4 ].arguments[ 0 ].fields.length).toBe(0)
expect(renderFieldArray.calls[ 4 ].arguments[ 0 ].fields.error)
.toExist()
.toBe('No dogs')
})

View File

@@ -19,58 +19,58 @@ const describeCreateFieldProps = (name, structure, expect) => {
expect(createFieldArrayProps(...defaultProps, {
dirty: false,
pristine: true
}).dirty).toBe(false)
}).fields.dirty).toBe(false)
expect(createFieldArrayProps(...defaultProps, {
dirty: false,
pristine: true
}).pristine).toBe(true)
}).fields.pristine).toBe(true)
expect(createFieldArrayProps(...defaultProps, {
dirty: true,
pristine: false
}).dirty).toBe(true)
}).fields.dirty).toBe(true)
expect(createFieldArrayProps(...defaultProps, {
dirty: true,
pristine: false
}).pristine).toBe(false)
}).fields.pristine).toBe(false)
})
it('should provide length', () => {
expect(createFieldArrayProps(...defaultProps, {
value: fromJS([])
}).length).toBe(0)
}).fields.length).toBe(0)
expect(createFieldArrayProps(...defaultProps, {
value: fromJS([ 'a' ])
}).length).toBe(1)
}).fields.length).toBe(1)
expect(createFieldArrayProps(...defaultProps, {
value: fromJS([ 'a', 'b' ])
}).length).toBe(2)
}).fields.length).toBe(2)
expect(createFieldArrayProps(...defaultProps, {
value: fromJS([ 'a', 'b', 'c' ])
}).length).toBe(3)
}).fields.length).toBe(3)
})
it('should provide errors', () => {
expect(createFieldArrayProps(...defaultProps, {}, 'Sync Error').error).toBe('Sync Error')
expect(createFieldArrayProps(...defaultProps, {}, 'Sync Error').valid).toBe(false)
expect(createFieldArrayProps(...defaultProps, {}, 'Sync Error').invalid).toBe(true)
expect(createFieldArrayProps(...defaultProps, {}, 'Sync Error').fields.error).toBe('Sync Error')
expect(createFieldArrayProps(...defaultProps, {}, 'Sync Error').fields.valid).toBe(false)
expect(createFieldArrayProps(...defaultProps, {}, 'Sync Error').fields.invalid).toBe(true)
expect(createFieldArrayProps(...defaultProps, {
asyncError: 'Async Error'
}).error).toBe('Async Error')
}).fields.error).toBe('Async Error')
expect(createFieldArrayProps(...defaultProps, {
asyncError: 'Async Error'
}).valid).toBe(false)
}).fields.valid).toBe(false)
expect(createFieldArrayProps(...defaultProps, {
asyncError: 'Async Error'
}).invalid).toBe(true)
}).fields.invalid).toBe(true)
expect(createFieldArrayProps(...defaultProps, {
submitError: 'Submit Error'
}).error).toBe('Submit Error')
}).fields.error).toBe('Submit Error')
expect(createFieldArrayProps(...defaultProps, {
submitError: 'Submit Error'
}).valid).toBe(false)
}).fields.valid).toBe(false)
expect(createFieldArrayProps(...defaultProps, {
submitError: 'Submit Error'
}).invalid).toBe(true)
}).fields.invalid).toBe(true)
})
it('should provide push', () => {
@@ -79,9 +79,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
value: fromJS([ 'a', 'b' ]),
arrayPush
})
expect(result.push).toBeA('function')
expect(result.fields.push).toBeA('function')
expect(arrayPush).toNotHaveBeenCalled()
expect(result.push('c')).toNotExist()
expect(result.fields.push('c')).toNotExist()
expect(arrayPush)
.toHaveBeenCalled()
.toHaveBeenCalledWith('c')
@@ -93,9 +93,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
value: fromJS([ 'a', 'b', 'c' ]),
arrayPop
})
expect(result.pop).toBeA('function')
expect(result.fields.pop).toBeA('function')
expect(arrayPop).toNotHaveBeenCalled()
expect(result.pop()).toBe('c')
expect(result.fields.pop()).toBe('c')
expect(arrayPop)
.toHaveBeenCalled()
.toHaveBeenCalledWith()
@@ -107,9 +107,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
value: fromJS([ 'a', 'b' ]),
arrayInsert
})
expect(result.insert).toBeA('function')
expect(result.fields.insert).toBeA('function')
expect(arrayInsert).toNotHaveBeenCalled()
expect(result.insert(1, 'c')).toNotExist()
expect(result.fields.insert(1, 'c')).toNotExist()
expect(arrayInsert)
.toHaveBeenCalled()
.toHaveBeenCalledWith(1, 'c')
@@ -121,9 +121,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
value: fromJS([ 'a', 'b' ]),
arrayRemove
})
expect(result.remove).toBeA('function')
expect(result.fields.remove).toBeA('function')
expect(arrayRemove).toNotHaveBeenCalled()
expect(result.remove(2)).toNotExist()
expect(result.fields.remove(2)).toNotExist()
expect(arrayRemove)
.toHaveBeenCalled()
.toHaveBeenCalledWith(2)
@@ -135,9 +135,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
value: fromJS([ 'a', 'b' ]),
arrayUnshift
})
expect(result.unshift).toBeA('function')
expect(result.fields.unshift).toBeA('function')
expect(arrayUnshift).toNotHaveBeenCalled()
expect(result.unshift('c')).toNotExist()
expect(result.fields.unshift('c')).toNotExist()
expect(arrayUnshift)
.toHaveBeenCalled()
.toHaveBeenCalledWith('c')
@@ -149,9 +149,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
value: fromJS([ 'a', 'b', 'c' ]),
arrayShift
})
expect(result.shift).toBeA('function')
expect(result.fields.shift).toBeA('function')
expect(arrayShift).toNotHaveBeenCalled()
expect(result.shift()).toBe('a')
expect(result.fields.shift()).toBe('a')
expect(arrayShift)
.toHaveBeenCalled()
.toHaveBeenCalledWith()
@@ -162,9 +162,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
const result = createFieldArrayProps(...defaultProps, {
value: fromJS([ 'a', 'b', 'c' ])
})
expect(result.forEach).toBeA('function')
expect(result.fields.forEach).toBeA('function')
expect(callback).toNotHaveBeenCalled()
result.forEach(callback)
result.fields.forEach(callback)
expect(callback).toHaveBeenCalled()
expect(callback.calls.length).toBe(3)
expect(callback.calls[ 0 ].arguments).toEqual([ 'foo[0]', 0 ])
@@ -177,9 +177,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
const result = createFieldArrayProps(...defaultProps, {
value: fromJS([ 'a', 'b', 'c' ])
})
expect(result.map).toBeA('function')
expect(result.fields.map).toBeA('function')
expect(callback).toNotHaveBeenCalled()
const mapResult = result.map(callback)
const mapResult = result.fields.map(callback)
expect(size(mapResult), 3)
expect(getIn(mapResult, 0)).toEqual({ whatever: true, name: 'foo[0]' })
expect(getIn(mapResult, 1)).toEqual({ whatever: true, name: 'foo[1]' })
@@ -197,9 +197,9 @@ const describeCreateFieldProps = (name, structure, expect) => {
arraySwap,
value: fromJS([ 'a', 'b', 'c' ])
})
expect(result.swap).toBeA('function')
expect(result.fields.swap).toBeA('function')
expect(arraySwap).toNotHaveBeenCalled()
expect(result.swap(0, 2)).toNotExist()
expect(result.fields.swap(0, 2)).toNotExist()
expect(arraySwap)
.toHaveBeenCalled()
.toHaveBeenCalledWith(0, 2)

View File

@@ -7,27 +7,29 @@ const createFieldArrayProps = (getIn, size, name,
const error = syncError || asyncError || submitError
const length = size(value)
return {
dirty,
error,
forEach: callback => (value || []).forEach((item, index) => callback(`${name}[${index}]`, index)),
insert: arrayInsert,
invalid: !!error,
length,
map: callback => (value || []).map((item, index) => callback(`${name}[${index}]`, index)),
pop: () => {
arrayPop()
return getIn(value, length - 1)
fields: {
dirty,
error,
forEach: callback => (value || []).forEach((item, index) => callback(`${name}[${index}]`, index)),
insert: arrayInsert,
invalid: !!error,
length,
map: callback => (value || []).map((item, index) => callback(`${name}[${index}]`, index)),
pop: () => {
arrayPop()
return getIn(value, length - 1)
},
pristine,
push: arrayPush,
remove: arrayRemove,
shift: () => {
arrayShift()
return getIn(value, 0)
},
swap: arraySwap,
unshift: arrayUnshift,
valid: !error
},
pristine,
push: arrayPush,
remove: arrayRemove,
shift: () => {
arrayShift()
return getIn(value, 0)
},
swap: arraySwap,
unshift: arrayUnshift,
valid: !error,
...rest
}
}