## State The `state` offers a way to create reactive values that can be used with tags to build dynamic and responsive web apps. This documentation will guide you through the usage of the `state` and `listState` function and its features. ## Table of Contents - [`state`](#state) - [`utilities`](#utilities) - [`stateAdd`](#stateadd) - [`stateAddAt`](#stateaddat) - [`stateRemove`](#stateremove) - [`stateRemoveWhere`](#stateremovewhere) - [Examples](#examples) - [Single Value State](#single-value-state) - [Object State](#object-state) - [Using With Arrays](#using-with-arrays) - [Conditional Rendering](#conditional-rendering) - [Template Rendering](#template-rendering) - [`listState`](#liststate) - [Example](#example) - [Properties](#properties) ## `state` When you create a `state` , it creates a [Observable](./Observable). Observables can then used across Cardboard for different things, take a look at the [Observables](./Observables) guide to get a better understanding on how they work. ### `utilities` There are a couple of utilities that can help with manipulating list states. #### `stateAdd` Add item to array `Observable`. ```ts const myList = state([]); stateAdd(myList, 4); // Adds 4 to myList ``` #### `stateAddAt` Add item at index in array `Observable`. ```ts const myList = state([]); stateAddAr(myList, 4, 2); // Adds 4 to myList at index 2 ``` #### `stateRemove` Remove item from array `Observable`. ```ts const myList = state([1]); stateRemove(myList, 1); // Removes item 1 from myList ``` #### `stateRemoveWhere` Remove item from array `Observable`. ```ts const myList = state([1]); stateRemove(myList, (item) => item == 1); // Removes item 1 from myList ``` ### Examples Here are some examples of how to use the `state` function and work with reactive state: #### Single Value State The simplest way of using the state is to make individual value states: ```javascript import { state } from 'cardboard-js/dist/cardboard.js'; const count = state(0); // Listen to changes in the entire state count.changed((count) => { console.log('Count changed:', count); }); // Modify the state and trigger change events count.value++; // Increment the count count.value = 3; // Set the count to 3 count.dispatch(3); // Set the count to 3 ``` #### Object State You can create states with any value you like. For examples you can create a state with an object instead of a primitive. ```ts import { state } from 'cardboard-js/dist/cardboard.js'; const { value, changed } = state({ count: 0 }); changed(({ count }) => { /* something in the object changed */ }); value.count++; div('There are no items').hideIf(value.count); // Will be hidden when the list contains items ``` #### Using With Arrays As mentioned above, you can also create array states: ```ts const st = state([]); st.value = [...st.value, 'new item']; const hasItems = notEmpty(st); div('There are no items').hideIf(hasItems); // Will be hidden when the list contains items ``` > `notEmpty` is a built-in compute helper, this means it returns a new [Observable](./Observables.md) that updates it's value when the state `st` changes. It will tell you if the list is empty or not. > Take a look at ["Computing"](./Observables#computing-observables) for a more detailed explanation. You can also use [`each`](./Logic#dynamic-list) to render lists dinamically. ```ts const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']; div( each(colors, (color) => button(color).addStyle('color', color) ) ); ``` #### Conditional Rendering You can conditionally/reactively change properties and do certain actions with tags. Like hiding an element, adding classes, etc... Take a look at [Conditional Element Manipulation](https://github.com/nombrekeff/cardboard-js/wiki/Manipulating-Tags#conditional-element-manipulation-methods) for more detailed explanations. ```ts import { state } from 'cardboard-js/dist/cardboard.js'; const isLoading = state(true); // Hide an element if isLoading is true div().hideIf(isLoading); // Disable an element if isLoading is true div().disableIf(isLoading); // Add class "loading" when isLoading is true, and add class "idle" when isLoading is false div() .classIf(isLoading, ['loading']) .classIfNot(isLoading, ['idle']) isLoading.value = false; ``` #### Template Rendering You can also use state to reactively update text. Take a look at [Managing Text](https://github.com/nombrekeff/cardboard-js/wiki/Managing-Text) for more detailed explanations. ```javascript import { state } from 'cardboard-js/dist/cardboard.js'; const st = state({ count: 0 }); // Create a div with a text that displays the count div(text('Count is: $count', st)); div().text('Count is: $count', st); div('Count is: ', st.count); ``` ## `listState` For handling lists you can create a `listState`, which gives some extra utilities, like adding/removing items, getting the count (as a consumable), etc... It also makes items into [Observables](./Observables), this way you can interact with items in more complex ways. List state returns a custom object instead of a Observable. It contains a `list` with the data, the **length** (_as a [Observable](./Observables)_), and methods to modify the data. You can then use the `list` as explained [here](#using-with-arrays), and you can also **add** and **remove** items from the list. ### Example ```ts import { listState } from './state.js'; const numbers = listState([1, 2]); div( each(numbers.list, (n) => p(`item ${n}`)) ); numbers.add(3); numbers.remove(2); numbers.addAt(4, 3); ``` > Any time the **numbers** change, `each` will update the content accordingly. ### Properties Once you have created a reactive list using `listState`, you can use the following methods and properties to manage and access the list: 1. **`add(item: T)`**: Adds an item to the end of the list. - `item` (T): The item to add to the list. 2. **`addAt(item: T, index: number)`**: Adds an item at a specific index in the list. - `item` (T): The item to add to the list. - `index` (number): The index at which to insert the item. 3. **`remove(item: T)`**: Removes an item from the list based on the value. - `item` (T): The item to remove from the list. 4. **`removeWhere(cb: (item: T) => boolean)`**: Removes items from the list based on a provided condition. - `cb` (Function): A callback function that returns `true` for items to be removed and `false` for items to be retained. 5. **`list` (Property):** The underlying [Observable](./Observables). You can use this property to access the list directly. 6. **`listValue` (Property):** A property that returns the current values of the reactive list as a regular array. 7. **`length` (Property):** A [Observable](./Observables) representing the current length of the list.