Reputation: 7959
I've come unstuck while building my first Svelte project. I've built a tree-view component in which each node has a checkbox; checkbox-change values should be passed down to the child nodes.
My tree-view consists of two components (TreeNode
is a class which contains, for example the text which should appear on each node):
<!-- TreeView.svelte -->
<script lang="ts">
import TreeNode from "./TreeNode";
import TreeNodeView from "./TreeNodeView.svelte";
export let isChecked: boolean = false;
export let treeNodes: Array<TreeNode>;
</script>
<ul role="group">
{#each treeNodes as treeNode ( treeNode.id )}
<TreeNodeView {isChecked} {treeNode} />
{/each}
</ul>
<!-- TreeNodeView.svelte -->
<script lang="ts">
import ...
let hasFocus: boolean = false;
function onChecked(e: CustomEvent<boolean>) {
isChecked = e.detail;
}
export let isChecked: boolean;
export let treeNode: TreeNode;
$:{
console.log(`${treeNode.text}.isChecked = ${isChecked}`);
}
</script>
<li>
</div>
{:else}
<div> </div>
{/if}
{#if treeNode.children.length === 0}
<Link href="~"><Checkbox labelText={treeNode.text} /></Link>
{:else}
<Checkbox checked={isChecked} labelText={treeNode.text} id={treeNode.id} name={treeNode.id} on:check={onChecked} />
{/if}
{#if treeNode.isSelected && treeNode.children.length}
<TreeView treeNodes={treeNode.children} {isChecked} />
{/if}
</li>
In the reactive block ($: { ... }
) it appears that the isChecked
value is being passed down, but none of the checkboxes reflect the updated value. I.e., when checking de-CH
in the following node...
I see this in the console...
... but the two child-node checkboxes remain stubbornly unchecked.
What have I missed?
[The styled components I'm using are carbon-components-svelte.]
UPDATE:
I realised that I had omitted the checked
binding in one of the checkboxes: In my TreeNodeView.svelte component I needed to add...
{#if treeNode.children.length === 0}
<Link href="~">
<Checkbox labelText={treeNode.text} checked={isChecked} /> // << checked={isChecked}
</Link>
{:else}
// ...
{/if}
What a silly mistake - sorry to anyone who gave this any thought.
Upvotes: 1
Views: 465
Reputation: 2795
If the change is not being reflected in the UI, it could be due to the way the checkbox component is handling its checked
prop. If the checkbox component is not properly reacting to changes in it's checked
prop, it might not update its internal state or the DOM correctly, even though the prop itself is being updated.
This way is to ensure that the checkbox component updates correctly when it's checked
prop changes. It is the use of two-way binding. You can use the bind:checked
directive to create a two-way binding between the checked
prop and the checkbox's internal state. This means that changes to the checkbox's state will update the checked
prop, and changes to the checked
prop will update the checkbox's state.
Example two-way binding for this;
<Checkbox bind:checked={isChecked} labelText={treeNode.text} id={treeNode.id} name={treeNode.id} on:check={onChecked} />
This should ensure that the checkbox's state is updated whenever the isChecked
prop changes, and vice versa.
If still problem with the above, It could be that the checkbox component is not properly handling the on:check
event. You could try using Svelte's built-in on:change
event instead, which is triggered whenever the checkbox's state changes. You could then update the isChecked
prop in the event handler.
Example;
<Checkbox checked={isChecked} labelText={treeNode.text} id={treeNode.id} name={treeNode.id} on:change={e => isChecked = e.target.checked} />
This will ensure that the isChecked
prop is updated whenever the checkbox's state changes, which should cause the component to re-render with the updated state.
In your TreeNodeView.svelte
component, you're using a CustomEvent
to update the isChecked
value. However, this event is only being listened to in the TreeNodeView
component itself, and not being passed up to the parent TreeView
component or any child components. This means that when you check a box, the isChecked
value is updated in the TreeNodeView
component, but this change isn't reflected in the parent or child components.
If so, you'll need to dispatch an event from the TreeNodeView
component whenever the checkbox is clicked, and listen for this event in the parent TreeView
component. When the event is fired, the parent component should update the isChecked
value for the corresponding TreeNode
and pass this new value down to the child components.
In TreeNodeView.svelte
, dispatch an event, so whenever a checkbox is clicked, the isChecked
value should be updated in the parent TreeView
component and passed down to the child components, updating the state of the checkboxes accordingly.
<script lang="ts">
// ...
function handleCheck(e: CustomEvent<boolean>, treeNode: TreeNode) {
treeNode.isChecked = e.detail;
}
// ...
</script>
<ul role="group">
{#each treeNodes as treeNode ( treeNode.id )}
<TreeNodeView {isChecked} {treeNode} on:check={(e) => handleCheck(e, treeNode)} />
{/each}
</ul>
Upvotes: 1