UNPKG

stimulus-value-bindings

Version:
260 lines (186 loc) 7.25 kB
# stimulus-value-bindings 🪢 _Reactive DOM value bindings for [Stimulus JS](https://stimulus.hotwired.dev)._ ![NPM Version](https://img.shields.io/npm/v/stimulus-value-bindings) [![CI](https://github.com/allmarkedup/stimulus-value-bindings/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/allmarkedup/stimulus-value-bindings/actions/workflows/ci.yml) ## Overview `stimulus-value-bindings` allows DOM element attribute values to be _reactively_ bound to Stimulus [controller values](https://stimulus.hotwired.dev/reference/values) so that the DOM attributes are automatically updated when their bound value property changes. Bindings are: * **reactive** - every time a value is changed any bound attributes (or text contents) in the DOM are automatically (and transparently) updated to reflect the changes. * **one-way** - the flow of updates is always from the controller to the DOM. Direct manipulation to bound attributes in the DOM will not result in the controller values being updated. `stimulus-value-bindings` can help you drastically reduce the amount of boring _something-has-changed-and-now-the-DOM-needs-updating_ code in your Stimulus JS controllers. > [!WARNING] > This documentation is a work-in-progress! Please open an issue if you are having problems. ## Simple counter example The example below is a simple 'counter' example that should help to demonstrate how reactive value bindings work. ▶️ [View this example running in JSBin](https://jsbin.com/hitotizesi/edit?html,output) ```js // counter-controller.js import { Controller } from "@hotwired/stimulus"; import { useValueBindings } from "stimulus-value-bindings"; export default class extends Controller { static values = { count: Number } connect(){ useValueBindings(this); } increment(){ this.countValue++; } decrement(){ this.countValue--; } } ``` ```html <div data-controller="counter"> <span id="count" data-counter-bind-text="countValue">0</span> <button data-action="counter#increment">+</button> <button data-action="counter#decrement">-</button> </div> ``` When the `+` or `-` buttons are clicked the `span#count` element text content will be automatically be updated to reflect the current value of the `count` controller value. The counter display is kept in sync with the `count` value without needing to manually update the DOM after each change. ## Installation Add the `stimulus-value-bindings` package to your `package.json`: #### Using NPM: ``` npm i stimulus-value-bindings --save ``` #### Using Yarn: ``` yarn add stimulus-value-bindings ``` ## Usage The `stimulus-value-bindings` package exports a `useValueBinding` function that can be used to add reactive value binding functionality to controllers. ```js import { Controller } from "@hotwired/stimulus"; import { useValueBindings } from "stimulus-value-bindings"; export default class extends Controller { connect(){ useValueBindings(this); } } ``` Alternatively, the package also exports a 'ready to go' `ValueBindingsController` base controller if you prefer to extend rather than compose your classes: ```js import { ValueBindingsController } from "stimulus-value-bindings"; export default class extends ValueBindingsController { // ... } ``` You can then delare [controller values](https://stimulus.hotwired.dev/reference/values) in the usual way, and bind DOM element attribute values and content to them using [binding data attributes](#binding-attributes). ```js // read-more-controller.js import { Controller } from "@hotwired/stimulus"; import { useValueBindings } from "stimulus-value-bindings"; export default class extends Controller { static values = { showMore: Boolean, buttonText: String } connect(){ useValueBindings(this); } toggle(){ this.openValue = !this.openValue; this.buttonTextValue = this.openValue ? "read less" : "read more"; } } ``` ```html <div data-controller="read-more"> <p>This is the summary content.</p> <button data-action="read-more#toggle" data-read-more-bind-text="buttonTextValue">read more</button> <p data-read-more-bind-hidden="!showMore" data-read-more-bind-aria-expanded="showMore" hidden> This is the additional content. </p> </div> ``` In the example above, clicking the `read more` button will toggle the `hidden` attribute on the 'additional content' `div` to hide or show it. The button text will additonally be updated to `read more` or `read less` according to whether the additional content is currently hidden or shown respectively. ## Adding bindings to elements Bindings are declared on DOM elements using data attributes with the following format: ``` data-[identifier]-bind-[bindingType]="[valueName]" ``` * `[identifier]`: The [identifier](https://stimulus.hotwired.dev/reference/controllers#identifiers) of the target controller * `[bindingType]`: See below for the types of bindings available. * `[valueName]` The name of the [value getter property](https://stimulus.hotwired.dev/reference/values#properties-and-attributes) to bind to. ### Attribute bindings The values of DOM element attributes can be bound to controller values using _attribute bindings_. ``` data-[identifier]-bind-[attribute-name]="[valueName]" ``` For example: ```js // defined in example-controller.js static values = { progress: 0 } ``` ```html <div data-controller="example"> <h4>Uploading...</h4> <progress data-example-bind-value="progressValue" max="100"></progress> </div> ``` #### Boolean attributes Boolean attributes will be added or removed according to the truthiness of the value they are bound to. ```js // defined in example-controller.js static values = { hidden: Boolean, } ``` ```html <div data-controller="example"> <div data-example-bind-hidden="hiddenValue">some content</div> </div> ``` * When `hiddenValue` is `true`, the `hidden` attribute will be added to the bound element. * When `hiddenValue` is `false`, the `hidden` attribute will be removed from the element. ### Element `textContent` binding The `textContent` of elements can be bound to controller values using _text bindings_. ``` data-[identifier]-bind-text="[valueName]" ``` For example: ```js // defined in example-controller.js static values = { count: Number } ``` ```html <div data-controller="example"> <span data-example-bind-text="countValue">0</span> </div> ``` ### Element bindings Elements can be bound to `Object`-type values. An attribute or content binding will be created for each of the object's properties. ``` data-[identifier]-bind="[valueName]" ``` For example: ```js // defined in example-controller.js static values = { input: { type: Object, default: { value: "default value", disabled: true } } } ``` ```html <div data-controller="example"> <input data-example-bind="inputValue"> <!-- renders: <input disabled="disabled" value="default value"> --> </div> ``` ## Credits `stimulus-value-bindings` is inspired by (and borrows code from!) the [`x-bind`](https://alpinejs.dev/directives/bind) functionality in Alpine JS. ## License `stimulus-value-bindings` is available as open source under the terms of the MIT License.