Concorde documentation (crawl) · interactive version

Concorde decorator — @bind. Binds a class property to a path in a publisher. The property updates when publisher data changes. Doc ID: docs/_decorators/bind. Keywords: Concorde, supersoniks, docs/_decorators/bind, bind, @bind, decorator, @state(), DataProviderKey, . Use , reflect: true, publisher.set(...). URL: https://concorde.supersoniks.org/crawl/docs/_decorators/bind.html.

@bind

Binds a class property to a path in a publisher. The property updates when publisher data changes.

For Lit re-renders, also add @state() on the same property.

See also: @subscribe, @handle, @publish, @get, @post, @put, @patch.

Principle

The decorator subscribes to the DataProvider store using dot notation or a DataProviderKey. Updates flow into the decorated property (Data flow).

Import

import { bind } from "@supersoniks/concorde/decorators";

Example

@customElement("demo-bind")
export class DemoBind extends LitElement {
  static styles = [tailwind];

  @bind("demoData.firstName")
  @state()
  firstName = "";

  @bind("demoData.lastName")
  @state()
  lastName: string = "";

  @bind("demoData.count")
  @state()
  count: number = 0;

  render() {
    return //......
  }

  updateData() {
    set(demoDataKey, { ...get(demoDataKey), count: get(demoDataKey).count + 1 });
    // see demo-bind in src/docs/example/decorators-demo-bind-demos.ts
    const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
    const randomUser = demoUsers.get()[randomIndex];
    demoData.set({
      firstName: randomUser.firstName,
      lastName: randomUser.lastName,
      count: (demoData.count.get() || 0) + 1,
    });
  }
}
<docs-demo-sources for="demo-bind"></docs-demo-sources>
    <demo-bind></demo-bind>

DataProviderKey (strict typing)

@bind accepts either a string path (legacy) or a DataProviderKey<T>. The property type must match T. Use reflect: true to push local writes back to the publisher (see below). See DataProviderKey.

import { bind } from "@supersoniks/concorde/decorators";
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";

type Data = { count: number };
const dataKey = new DataProviderKey<Data>("data");

@bind(dataKey.count, { reflect: true })
@state()
count: number = 0;

Reflect (reflect: true)

Two-way sync: reads from the publisher and local assignments call publisher.set(...). An internal guard avoids infinite loops.

@bind("userData.profile.avatarUrl", { reflect: true })
@state()
avatar: string;
@customElement("demo-bind-reflect")
export class DemoBindReflect extends LitElement {
  static styles = [tailwind];

  @bind("bindReflectDemo.count", { reflect: true })
  @state()
  withReflect: number = 0;

  @bind("bindReflectDemo.count")
  @state()
  withoutReflect: number = 0;

  render() {
    return html`
      <div class="mb-3">
        from publisher : ${sub("bindReflectDemo.count") || 0} <br />
        from component with reflect : ${this.withReflect || 0} <br />
        from component without reflect : ${this.withoutReflect || 0}
      </div>
      <sonic-button @click=${() => this.withReflect++}
        >Increment with reflect</sonic-button
      >
      <sonic-button @click=${() => this.withoutReflect++}
        >Increment without reflect</sonic-button
      >
    `;
  }
}
<docs-demo-sources for="demo-bind-reflect"></docs-demo-sources>
    <demo-bind-reflect></demo-bind-reflect>

Path syntax

Dynamic paths

Use ${prop} or ${this.prop} inside a normal string literal (not a JS template literal with backticks). @bind re-subscribes when a reactive dependency changes. While a placeholder is null/undefined, the bind is inactive; optional { skipEmptyPlaceholder: true } also waits on "". See Dynamic path placeholders.

Properties referenced in the pattern must be reactive (@property, etc.) or you must call requestUpdate manually.

<docs-demo-sources for="demo-bind-dynamic"></docs-demo-sources>
    <demo-bind-dynamic></demo-bind-dynamic>

Behavior

Notes

Works with any component that has the usual DOM lifecycle (LitElement, Subscriber mixin, etc.).

Shared data: Sharing data.