Skip to content

Binding Concepts

Overview

Data binding connects component properties to your application's state — declarations and API services — so the UI reflects current data without requiring manual DOM manipulation. This page explains the core model: what a binding is, how bindings are evaluated, when they update, and the difference between binding directions.

What You Will Learn

  • What a binding is and how expressions are evaluated
  • How Bellini keeps bindings in sync with application state
  • The difference between one-way and two-way binding
  • How binding scope controls what data is accessible in each context

When To Use This

Use this when you need to understand how data binding works in Bellini before writing expressions or troubleshooting unexpected component behaviour.


What a Binding Is

A binding is an expression assigned to a component property. The expression is a JavaScript snippet evaluated in the context of the current page or component. It has access to:

  • All declarations on the page or component, via $ctrl (e.g. $ctrl.items, $ctrl.currentUser.name)
  • All injected services, also via $ctrl by their declared name (e.g. $ctrl.myApiService.getUsers())

The result of the expression becomes the value of the property. For example:

Property Expression Result
Table Data $ctrl.myApiService.getUsers() The table is populated with the API response
Button Disabled $ctrl.form.invalid The button is disabled when the form is invalid
Text Input Value $ctrl.selectedItem.name The input displays the selected item's name

Bindings are configured in the Properties view by clicking the edit icon or expression icon next to a property. For more, see Using Components.


How Bindings Stay in Sync

Bellini re-evaluates all active bindings automatically after any operation that can change application state — user interactions (clicks, input changes), function calls, API responses, and timers. You do not need to manually notify the UI that data has changed; as long as state is updated through normal Bellini-managed operations, all bound properties will reflect the latest values.

For example:

  1. A button's Click handler calls a function that sets $ctrl.selectedItem to a new value.
  2. Bellini detects the state change and re-evaluates all bindings.
  3. Every component property bound to $ctrl.selectedItem (or any of its child properties) updates automatically.

This means the typical pattern is: update a declaration → the UI updates itself.

Multiple Updates in a Single Operation

When a single operation updates multiple declarations — for example, a function that sets $ctrl.isLoading, $ctrl.items, and $ctrl.selectedItem in sequence — Bellini processes all the changes together and re-evaluates bindings once at the end of the operation. The UI updates a single time regardless of how many declarations were changed, so there is no risk of intermediate renders or flickering.


Binding Direction

Binding direction describes how data flows between the declaration and the component. The direction is determined by the export type set on a component's exported declaration — not by anything the user configures at the binding site. When you write an expression on a property, the one-way or two-way behaviour is already set and applied automatically.

For built-in components, all export types are pre-configured — you can rely on them behaving as expected. For custom components, the developer who builds the component sets the export type on each exported declaration. See Component Properties for details.

One-way Binding

In one-way binding, data flows from the declaration into the component property. The component reads the value but cannot write back to it. This is suitable for any property that only needs to display or react to data — visibility, labels, display values, disabled states, and so on.

Most component properties use one-way binding.

Two-way Binding

In two-way binding, data flows in both directions. The declaration drives the component's displayed value, and changes made by the user (such as typing in a text field or toggling a switch) are written back to the declaration automatically.

Two-way binding is used on form input properties where the component captures user input that should be stored in a declaration — for example, a Text Input's Value bound to $ctrl.form.email.


Binding Scope

Bindings are always evaluated in the scope of the page or component that owns the property being bound. This means:

  • Bindings on a page have access to the page's declarations and its injected services.
  • Bindings on a custom component have access to the component's own declarations and its injected services — not the parent page's declarations.
  • Data is passed into a custom component via its exported properties, not by reaching into the parent scope.

This scope isolation keeps components self-contained and reusable across different pages.


Helpful Resources

  • Expressions — Write expressions to bind component properties to declarations and services
  • Iterating Over Data — Repeat components over arrays using the Iterate property
  • Declarations — Create and manage declarations on pages and components
  • Component Properties — Configure exported properties for custom components
  • Community Q&A: Bellini Community
    Have a question? Post or search it here.