COOKBOOK / LIVE EXAMPLE
Nested Lists example with VSN.js
Real markup. Real VSN. Try it below.
← All examples · Open full screen ↗
View example source
<section id="nested-list-example" class="example-card cookbook-example">
<header class="cookbook-heading">
<div>
<p class="cookbook-eyebrow">cookbook</p>
<h1>Nested list scopes</h1>
<p class="cookbook-lede">
Each row receives an item and index scope while its actions call functions from the parent behavior.
</p>
</div>
<span class="cookbook-badge">each + scopes</span>
</header>
<form class="cookbook-toolbar cookbook-inline-form" vsn-on:submit!prevent="add();">
<input class="cookbook-input" type="text" placeholder="Add a task" autocomplete="off" vsn-bind="newLabel" />
<button class="btn" type="submit">Add task</button>
<span class="cookbook-status"><strong vsn-bind:from="total">0</strong> rows</span>
</form>
<ul class="cookbook-list">
<template vsn-each="items as item, index" vsn-key="item.0">
<li class="cookbook-list-row">
<span class="cookbook-list-index" vsn-bind:from="index">0</span>
<span class="cookbook-list-label" vsn-bind:from="item[0]">Task</span>
<span class="cookbook-list-state"></span>
<button class="btn secondary" type="button" vsn-on:click="toggle(index);">Toggle</button>
<button class="ghost" type="button" vsn-on:click="remove(index);">Remove</button>
</li>
</template>
</ul>
<p class="cookbook-note">
The stable task label keys each row, so replacing or reordering the array preserves row identity.
</p>
</section>
<script type="text/vsn">
#nested-list-example {
newLabel: "";
items: [
["Review the schema", false],
["Render the fragment", true],
["Run the browser check", false]
];
total: 0;
construct {
sync();
}
sync() {
total = items.length;
}
add() {
label = newLabel.trim();
if (label != "") {
items = items.concat([[label, false]]);
newLabel = "";
sync();
}
}
toggle(index) {
item = items[index];
updated = [item[0], !item[1]];
items = items.slice(0, index).concat([updated]).concat(items.slice(index + 1));
sync();
}
remove(index) {
items = items.slice(0, index).concat(items.slice(index + 1));
sync();
}
.cookbook-list-row {
@class :< { "is-done": item[1] };
}
.cookbook-list-state {
@html :< (item[1] ? "Done" : "Open");
}
}
</script>