11import  AddButton  from  "../AddButton" ; 
22import  IconButton  from  "../IconButton" ; 
33import  React ,  {  Component  }  from  "react" ; 
4+ import  {  polyfill  }  from  "react-lifecycles-compat" ; 
45import  includes  from  "core-js/library/fn/array/includes" ; 
56import  *  as  types  from  "../../types" ; 
67
@@ -18,6 +19,7 @@ import {
1819 toIdSchema , 
1920 getDefaultRegistry , 
2021}  from  "../../utils" ; 
22+ import  shortid  from  "shortid" ; 
2123
2224function  ArrayFieldTitle ( {  TitleField,  idSchema,  title,  required } )  { 
2325 if  ( ! title )  { 
@@ -44,7 +46,7 @@ function DefaultArrayItem(props) {
4446 fontWeight : "bold" , 
4547 } ; 
4648 return  ( 
47-  < div  key = { props . index }  className = { props . className } > 
49+  < div  key = { props . key }  className = { props . className } > 
4850 < div  className = { props . hasToolbar  ? "col-xs-9"  : "col-xs-12" } > 
4951 { props . children } 
5052 </ div > 
@@ -174,6 +176,25 @@ function DefaultNormalArrayFieldTemplate(props) {
174176 ) ; 
175177} 
176178
179+ function  generateRowId ( )  { 
180+  return  shortid . generate ( ) ; 
181+ } 
182+ 
183+ function  generateKeyedFormData ( formData )  { 
184+  return  ! Array . isArray ( formData ) 
185+  ? [ ] 
186+  : formData . map ( item  =>  { 
187+  return  { 
188+  key : generateRowId ( ) , 
189+  item, 
190+  } ; 
191+  } ) ; 
192+ } 
193+ 
194+ function  keyedToPlainFormData ( keyedFormData )  { 
195+  return  keyedFormData . map ( keyedItem  =>  keyedItem . item ) ; 
196+ } 
197+ 
177198class  ArrayField  extends  Component  { 
178199 static  defaultProps  =  { 
179200 uiSchema : { } , 
@@ -185,6 +206,32 @@ class ArrayField extends Component {
185206 autofocus : false , 
186207 } ; 
187208
209+  constructor ( props )  { 
210+  super ( props ) ; 
211+  const  {  formData }  =  props ; 
212+  const  keyedFormData  =  generateKeyedFormData ( formData ) ; 
213+  this . state  =  { 
214+  keyedFormData, 
215+  } ; 
216+  } 
217+ 
218+  static  getDerivedStateFromProps ( nextProps ,  prevState )  { 
219+  const  nextFormData  =  nextProps . formData ; 
220+  const  previousKeyedFormData  =  prevState . keyedFormData ; 
221+  const  newKeyedFormData  = 
222+  nextFormData . length  ===  previousKeyedFormData . length 
223+  ? previousKeyedFormData . map ( ( previousKeyedFormDatum ,  index )  =>  { 
224+  return  { 
225+  key : previousKeyedFormDatum . key , 
226+  item : nextFormData [ index ] , 
227+  } ; 
228+  } ) 
229+  : generateKeyedFormData ( nextFormData ) ; 
230+  return  { 
231+  keyedFormData : newKeyedFormData , 
232+  } ; 
233+  } 
234+ 
188235 get  itemTitle ( )  { 
189236 const  {  schema }  =  this . props ; 
190237 return  schema . items . title  ||  schema . items . description  ||  "Item" ; 
@@ -217,24 +264,40 @@ class ArrayField extends Component {
217264
218265 onAddClick  =  event  =>  { 
219266 event . preventDefault ( ) ; 
220-  const  {  schema,  formData ,   registry =  getDefaultRegistry ( )  }  =  this . props ; 
267+  const  {  schema,  registry =  getDefaultRegistry ( ) ,  onChange  }  =  this . props ; 
221268 const  {  definitions }  =  registry ; 
222269 let  itemSchema  =  schema . items ; 
223270 if  ( isFixedItems ( schema )  &&  allowAdditionalItems ( schema ) )  { 
224271 itemSchema  =  schema . additionalItems ; 
225272 } 
226-  this . props . onChange ( [ 
227-  ...formData , 
228-  getDefaultFormState ( itemSchema ,  undefined ,  definitions ) , 
229-  ] ) ; 
273+  const  newFormDataRow  =  getDefaultFormState ( 
274+  itemSchema , 
275+  undefined , 
276+  definitions 
277+  ) ; 
278+  const  newKeyedFormData  =  [ 
279+  ...this . state . keyedFormData , 
280+  { 
281+  key : generateRowId ( ) , 
282+  item : newFormDataRow , 
283+  } , 
284+  ] ; 
285+ 
286+  this . setState ( 
287+  { 
288+  keyedFormData : newKeyedFormData , 
289+  } , 
290+  ( )  =>  onChange ( keyedToPlainFormData ( newKeyedFormData ) ) 
291+  ) ; 
230292 } ; 
231293
232294 onDropIndexClick  =  index  =>  { 
233295 return  event  =>  { 
234296 if  ( event )  { 
235297 event . preventDefault ( ) ; 
236298 } 
237-  const  {  formData,  onChange }  =  this . props ; 
299+  const  {  onChange }  =  this . props ; 
300+  const  {  keyedFormData }  =  this . state ; 
238301 // refs #195: revalidate to ensure properly reindexing errors 
239302 let  newErrorSchema ; 
240303 if  ( this . props . errorSchema )  { 
@@ -249,7 +312,13 @@ class ArrayField extends Component {
249312 } 
250313 } 
251314 } 
252-  onChange ( formData . filter ( ( _ ,  i )  =>  i  !==  index ) ,  newErrorSchema ) ; 
315+  const  newKeyedFormData  =  keyedFormData . filter ( ( _ ,  i )  =>  i  !==  index ) ; 
316+  this . setState ( 
317+  { 
318+  keyedFormData : newKeyedFormData , 
319+  } , 
320+  ( )  =>  onChange ( keyedToPlainFormData ( newKeyedFormData ) ,  newErrorSchema ) 
321+  ) ; 
253322 } ; 
254323 } ; 
255324
@@ -259,7 +328,7 @@ class ArrayField extends Component {
259328 event . preventDefault ( ) ; 
260329 event . target . blur ( ) ; 
261330 } 
262-  const  {  formData ,   onChange }  =  this . props ; 
331+  const  {  onChange }  =  this . props ; 
263332 let  newErrorSchema ; 
264333 if  ( this . props . errorSchema )  { 
265334 newErrorSchema  =  { } ; 
@@ -275,18 +344,24 @@ class ArrayField extends Component {
275344 } 
276345 } 
277346
347+  const  {  keyedFormData }  =  this . state ; 
278348 function  reOrderArray ( )  { 
279349 // Copy item 
280-  let  newFormData  =  formData . slice ( ) ; 
350+  let  _newKeyedFormData  =  keyedFormData . slice ( ) ; 
281351
282352 // Moves item from index to newIndex 
283-  newFormData . splice ( index ,  1 ) ; 
284-  newFormData . splice ( newIndex ,  0 ,  formData [ index ] ) ; 
353+  _newKeyedFormData . splice ( index ,  1 ) ; 
354+  _newKeyedFormData . splice ( newIndex ,  0 ,  keyedFormData [ index ] ) ; 
285355
286-  return  newFormData ; 
356+  return  _newKeyedFormData ; 
287357 } 
288- 
289-  onChange ( reOrderArray ( ) ,  newErrorSchema ) ; 
358+  const  newKeyedFormData  =  reOrderArray ( ) ; 
359+  this . setState ( 
360+  { 
361+  keyedFormData : newKeyedFormData , 
362+  } , 
363+  ( )  =>  onChange ( keyedToPlainFormData ( newKeyedFormData ) ,  newErrorSchema ) 
364+  ) ; 
290365 } ; 
291366 } ; 
292367
@@ -367,7 +442,8 @@ class ArrayField extends Component {
367442 const  itemsSchema  =  retrieveSchema ( schema . items ,  definitions ) ; 
368443 const  arrayProps  =  { 
369444 canAdd : this . canAddItem ( formData ) , 
370-  items : formData . map ( ( item ,  index )  =>  { 
445+  items : this . state . keyedFormData . map ( ( keyedItem ,  index )  =>  { 
446+  const  {  key,  item }  =  keyedItem ; 
371447 const  itemSchema  =  retrieveSchema ( schema . items ,  definitions ,  item ) ; 
372448 const  itemErrorSchema  =  errorSchema  ? errorSchema [ index ]  : undefined ; 
373449 const  itemIdPrefix  =  idSchema . $id  +  "_"  +  index ; 
@@ -379,6 +455,7 @@ class ArrayField extends Component {
379455 idPrefix 
380456 ) ; 
381457 return  this . renderArrayFieldItem ( { 
458+  key, 
382459 index, 
383460 canMoveUp : index  >  0 , 
384461 canMoveDown : index  <  formData . length  -  1 , 
@@ -544,7 +621,8 @@ class ArrayField extends Component {
544621 disabled, 
545622 idSchema, 
546623 formData, 
547-  items : items . map ( ( item ,  index )  =>  { 
624+  items : this . state . keyedFormData . map ( ( keyedItem ,  index )  =>  { 
625+  const  {  key,  item }  =  keyedItem ; 
548626 const  additional  =  index  >=  itemSchemas . length ; 
549627 const  itemSchema  =  additional 
550628 ? retrieveSchema ( schema . additionalItems ,  definitions ,  item ) 
@@ -565,6 +643,7 @@ class ArrayField extends Component {
565643 const  itemErrorSchema  =  errorSchema  ? errorSchema [ index ]  : undefined ; 
566644
567645 return  this . renderArrayFieldItem ( { 
646+  key, 
568647 index, 
569648 canRemove : additional , 
570649 canMoveUp : index  >=  itemSchemas . length  +  1 , 
@@ -597,6 +676,7 @@ class ArrayField extends Component {
597676
598677 renderArrayFieldItem ( props )  { 
599678 const  { 
679+  key, 
600680 index, 
601681 canRemove =  true , 
602682 canMoveUp =  true , 
@@ -658,6 +738,7 @@ class ArrayField extends Component {
658738 hasMoveDown : has . moveDown , 
659739 hasRemove : has . remove , 
660740 index, 
741+  key, 
661742 onDropIndexClick : this . onDropIndexClick , 
662743 onReorderClick : this . onReorderClick , 
663744 readonly, 
@@ -669,4 +750,6 @@ if (process.env.NODE_ENV !== "production") {
669750 ArrayField . propTypes  =  types . fieldProps ; 
670751} 
671752
753+ polyfill ( ArrayField ) ; 
754+ 
672755export  default  ArrayField ; 
0 commit comments