pablo-abc / felte

An extensible form library for Svelte, Solid and React
https://felte.dev
MIT License
1.01k stars 44 forks source link

Field Arrays' delete on index removes also later elements #114

Open Alphenus opened 2 years ago

Alphenus commented 2 years ago

Describe the bug When attempting to remove a field from a field array at index i using unsetField('fieldArray${index}'), all members of that array from i to end get removed.

I tried to use alternative ways to remove single entries (e.g. slicing and combining arrays), but same issue re-occurs. However, when replicating similar form without felte using a local variable as 'store', it works as expected.

To Reproduce Steps to reproduce the behavior:

  1. Grab code from https://felte.dev/docs/svelte/field-arrays
  2. Create multiple new interest items
  3. Attempt to remove some of the first items
  4. All items after that get removed

Expected behavior Only the selected item should disappear.

Screenshots By reactively logging interests -variable ($: console.log(interests)), it is shown that elemets are removed one-by-one from the array after calling remove function: image

Environment (please complete the following information):

Other stuff I'm quite new with svelte, so this can be user error of sort.

pablo-abc commented 2 years ago

Thanks for the report! This seems to be an issue on my side. But it works if you remove the (interest.key) part.

<script>
  import { createForm } from 'felte';

  const { form, data, addField, unsetField } = createForm({
    initialValues: {
      interests: [{ value: '' }],
    },
  });

  $: interests = $data.interests;

  function removeInterest(index) {
    return () => unsetField(`interests.${index}`);
  }

  function addInterest(index) {
    return () => addField(`interests`, { value: '' }, index);
  }
</script>

<form use:form>
  {#each interests as interest, index}
    <div>
      <input name="interests.{index}.value" />
      <button type="button" on:click="{addInterest(index + 1)}">
        Add Interest
      </button>
      <button type="button" on:click="{removeInterest(index)}">
        Remove Interest
      </button>
    </div>
  {/each}
</form>

I'll update the documentation for now but will leave this open to check why adding a key breaks this.

pablo-abc commented 2 years ago

As a further update. I'm not sure how I did not catch this before but: If you want to key your items (using interest.key like the example), add the attribute data-felte-keep-on-remove to the<input> element.

I'm not quite sure how this did not cause any conflicts before. But that'd be the recommendation for now. Key your items + add the attribute to any input within your each.

pierre-H commented 1 year ago

Did someone find another solution ? I tried to use key + data-felte-keep-on-remove in a fieldset inside the loop but I have the same problem as @Alphenus . @pablo-abc

pierre-H commented 1 year ago

What I mean is that : I use key and data-felte-keep-on-remove and I try to set the data programmatically.

Only one line is setted if I use $data = ... or setData. Here is the result with a $: console.log($data.items); : image

If I use setInitialValues with reset I've got an error because step by step the items becomes undefined.

gl-aagostino commented 1 year ago

I have a similar problem where upon removing a field via unsetField a completely different array field loses all of its data. I've tried about 100 different ways to work around it, but it seems to be hellbent on wiping the data from another array. This happens to be an array of selects. I wonder if that has anything to do with it.

ChrisOgden commented 1 year ago

I have a similar problem where upon removing a field via unsetField a completely different array field loses all of its data. I've tried about 100 different ways to work around it, but it seems to be hellbent on wiping the data from another array. This happens to be an array of selects. I wonder if that has anything to do with it.

I am seeing this as well, it isn't always consistent either. In my case I have an array of items which have sub-values. For example in my testing just now I had

Before Delete

"step1": { 
   "item_fczxfm0p": { 
      "fldOvLgT8NrE7ZEOT": "1", 
      "fldcVoNTkahMLtrJR": "", 
      "fldp3O05kE14AC0Kn": "" 
   }, 
   "item_0y8l9ofczxfm": { 
      "fldOvLgT8NrE7ZEOT": "2", 
      "fldcVoNTkahMLtrJR": "", 
      "fldp3O05kE14AC0Kn": "" 
   }, 
   "item_gmjsl7keutr": { 
      "fldOvLgT8NrE7ZEOT": "3",
      "fldcVoNTkahMLtrJR": "", 
      "fldp3O05kE14AC0Kn": ""  
   } 
 }

After

"step1": { 
   "item_0y8l9ofczxfm": { 
      "fldOvLgT8NrE7ZEOT": "2", 
      "fldcVoNTkahMLtrJR": "", 
      "fldp3O05kE14AC0Kn": "" 
    }, 
   "item_gmjsl7keutr": { 
      "fldOvLgT8NrE7ZEOT": "3" 
    } 
 }

I only deleted the first item but fields in the third item disappeared

ChrisOgden commented 1 year ago

On continued investigation I found the following. I am dynamically generating the HTML elements, so clicking add item adds a new object to the step1 array of HTML elements to be generated.

The problem goes away when I use delete to remove the object from HTML array vs using array.splice, this creates a new problem though because I now have an object with bogus lengths since there are empty elements.

At this point I think I am going to have to work around this scenario since the reactivity with felte appears broken for this use case

mpicciolli commented 10 months ago

I had the same problem #230 but I didn't find a solution. Any news @ChrisOgden ?

canastro commented 8 months ago

Yeah this issue is a bit inconvenient as it prevents you from using animate:flip

ChrisOgden commented 8 months ago

I had the same problem #230 but I didn't find a solution. Any news @ChrisOgden ?

I did something along the lines of this:

const isDirty = steps[stepIndex][rIndex].dirty
if (isDirty) {
    unsetField(`${sKey}.${rKey}`)
}
delete steps[stepIndex][rIndex]
const cleanSteps = _.filter(steps[stepIndex])

It is a little out of context and seems messy but it appears to have worked around it. I know I played with it a lot to get to this point. The challenge with mine is the elements are being dynamically rendered based on an object separate from the form values object.