My code is working, but I just wonder if there's a tidier way of achieving what I've done with some de-structuring. Essentially I've started of from the code here:
https://svelte.dev/repl/2441993f8d9946aa894bf07a8a8f9b4f?version=3.52.0
and nest the array within an object and added a delete button like so:
<script>
let f={
"name" : "", "type" : "",
"values":[{ "label": "", "start": "", "end": "" },
{ "label": "", "start": "", "end": "" },
{ "label": "", "start": "", "end": "" }]
};
// let { name, type, values } = f
const addField = () => {f.values = [...f.values, {label: '', start: '', end: ''}]};
const removeField = (v, i) => {f.values = f.values.filter((e, id) => id!=i)}
</script>
<input type="text" bind:value={f.name} placeholder="name"/>
<input type="text" bind:value={f.type} placeholder="type"/>
{#each f.values as v, i}
<div>
<input id={i} type="text" bind:value={f.values[i].start} placeholder="start"/>
<input id={i} type="text" bind:value={f.values[i].end} placeholder="end"/>
<input id={i} type="text" bind:value={f.values[i].label} placeholder="label"/>
<input id={i} type="button" value="X" on:click={removeField(v, i)}>
</div>
{/each}
<button on:click|preventDefault={addField}>Add</button>
<button on:click={() => console.log(f.values)}>Save</button>
<pre>
{JSON.stringify(f, null, 2)}
</pre>
As far as I've tested it it appears to work, but I just wonder if there's easier ways to bind nested values of the object, so the code looks a little cleaner rather than referencing 'f.' everywhere.
When I've tried referencing the de-structured values the binding gets lost - I suppose this is normal behaviour.
CodePudding user response:
In the #each
the v
variable will be the current item which you can use directly:
{#each values as v, i}
<div>
<input type="text" bind:value={v.start} placeholder="start"/>
<input type="text" bind:value={v.end} placeholder="end"/>
<input type="text" bind:value={v.label} placeholder="label"/>
<input type="button" value="X" on:click={removeField(v, i)}>
</div>
{/each}
For the script part, there would be certain ugly workarounds with re-assignments or dummy assignments, but the cleanest solution would probably be to extract everything about the values into a separate component, e.g.
<!-- Values.svelte -->
<script>
export let values;
const addField = () => {values = [...values, {label: '', start: '', end: ''}]};
const removeField = item => {values = values.filter(x => x != item)}
</script>
{#each values as v, i}
<div>
<input type="text" bind:value={v.start} placeholder="start"/>
<input type="text" bind:value={v.end} placeholder="end"/>
<input type="text" bind:value={v.label} placeholder="label"/>
<input type="button" value="X" on:click={removeField(v)}>
</div>
{/each}
<button on:click|preventDefault={addField}>Add</button>
Which then can be added as:
<Values bind:values={f.values} />
(By the way, id
attributes are not allowed to start with numbers and have to be unique in the entire page.)