Star

Created With

Lists


1linkimport { List } from 'callbag-jsx';

2link

3linkconst records = state([]);

4linkconst add = () => records.set(records.get().concat(new Date()));

5linkconst clear = () => records.set([]);

6link

7linkrenderer.render(

8link <>

9link <button onclick={add}>Add</button>

10link <button onclick={clear}>Clear</button>

11link <ul>

12link <List of={records} each={record => <li>{record}</li>}/>

13link </ul>

14link </>

15link).on(document.body);

Playground

👉 each() function will be provided with a state object, reflecting the value of a particular index.
👉 Use .sub() method to read/track its properties:

1linkconst todos = state([{title: 'Do this'}, {title: 'Do that'}]);

2linkconst next = state('');

3link

4linkconst add = () => {

5link todos.set(todos.get().concat([{title: next.get()}]));

6link next.set('');

7link};

8link

9linkrenderer.render(

10link <>

11link <h1>Todos</h1>

12link <ol>

13link <List of={todos} each={todo => <li>{todo.sub('title')}</li>}/>

14link </ol>

15link <input type='text' _state={next} placeholder='What should be done?'/>

16link <button onclick={add}>Add</button>

17link </>

18link).on(document.body);

PlaygroundLearn More

👉 Use .get() method to get a snapshot value. This can be useful for handling events on items of the list:

1linkconst records = state([]);

2linkconst add = () => records.set(records.get().concat(new Date()));

3linkconst clear = () => records.set([]);

4linkconst remove = date => records.set(records.get().filter(d => d !== date));

5link

6linkrenderer.render(

7link <>

8link <button onclick={add}>Add</button>

9link <button onclick={clear}>Clear</button>

10link

11link <br/>

12link

13link <small>

14link Click on each record to remove it.

15link </small>

16link <ul>

17link <List of={records} each={record =>

18link <li onclick={() => remove(record.get())}>

19link {record}

20link </li>}/>

21link </ul>

22link </>

23link).on(document.body);

Playground



linkIndexes

The index of each element is passed to each() as a second argument:

1linkconst records = state([]);

2linkconst add = () => records.set(records.get().concat(new Date()));

3linkconst clear = () => records.set([]);

4linkconst remove = (date) => records.set(records.get().filter(d => d !== date));

5link

6linkrenderer.render(

7link <>

8link <button onclick={add}>Add</button>

9link <button onclick={clear}>Clear</button>

10link

11link <br/>

12link

13link <small>

14link Click on each record to remove it.

15link </small>

16link

17link <List of={records} each={(record, index) =>

18link <div onclick={() => remove(record.get())} class={{odd: index % 2}}>

19link {index + 1} - {record}

20link </div>}

21link />

22link </>

23link).on(document.body);

Playground



linkKeyed Lists

By default, DOM elements (returned by each()) are bound to a specific index. This means, for example, if you prepend an item to your array, contents of all DOM elements will be updated (since the content of all indices of the array have changed):

In some cases, this ☝️ is not the desired behavior. For example:

You change this behavior by providing a mapping between items of your list and DOM elements, in form of a key function:

1link// map each element to a property

2link//

3linkconst key = x => x.id

4link

5link// or, when list items are unique strings,

6link// use them directly as keys

7link//

8linkconst key = x => x

👉 Pass a key function to key property of <List/> for smarter DOM updates:

1linkconst tasks = state([]);

2linkconst next = state('');

3linklet id = 0;

4link

5linkconst add = () => {

6link const newTask = {

7link id: id,

8link title: next.get()

9link };

10link

11link id += 1;

12link next.set('');

13link tasks.set(tasks.get().concat(newTask));

14link}

15link

16linkrenderer.render(

17link <>

18link <input type='text' _state={next}/>

19link <button onclick={add}>Add</button>

20link

21link <br/>

22link

23link <List of={tasks}

24link each={task => <div>{task.sub('title')} ({task.sub('id')})</div>}

25link key={task => task.id}

26link />

27link </>

28link).on(document.body);

Playground

info IMPORTANT

The key function passed to MUST return stable and unique strings (or numbers):


👉 When key is provided, each() will be invoked for each unique key (instead of index). As the index of that key can change, index parameter passed to each() will become a callbag (instead of a fixed number):

1linkconst tasks = state([]);

2linkconst next = state('');

3linklet id = 0;

4link

5linkconst add = () => {

6link const newTask = {

7link id: id,

8link title: next.get()

9link };

10link

11link id += 1;

12link next.set('');

13link tasks.set(tasks.get().concat(newTask));

14link}

15link

16linkconst remove = task => {

17link tasks.set(tasks.get().filter(t => t.id !== task.id));

18link}

19link

20linkrenderer.render(<>

21link <input type='text' _state={next}/>

22link <button onclick={add}>Add</button>

23link

24link <br/>

25link <small>Click on each item to remove it</small>

26link

27link <List of={tasks}

28link each={(task, index) =>

29link <div class={{odd: expr($ => $(index) % 2)}}

30link onclick={() => remove(task.get())}>

31link {expr($ => $(index) + 1)} - {task.sub('title')} ({task.sub('id')})

32link </div>

33link }

34link key={task => task.id}

35link />

36link</>).on(document.body);

Playground





IndexesKeyed Lists

Home Getting Started


Introductionchevron_right

Basicschevron_right

Reactivitychevron_right

Componentschevron_right

In-Depthchevron_right

Metachevron_right