or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

binding.mdcomponents.mdindex.mdobservables.mdperformance.mdtemplates.mdutils.md
tile.json

binding.mddocs/

0

# Data Binding System

1

2

Declarative binding system that connects view models to DOM elements with automatic synchronization and a rich set of built-in binding handlers. The binding system uses `data-bind` attributes to establish connections between HTML elements and JavaScript data.

3

4

## Capabilities

5

6

### Binding Application

7

8

Functions to apply data bindings between view models and DOM elements.

9

10

```javascript { .api }

11

/**

12

* Apply bindings to connect view model to DOM

13

* @param viewModel - The view model object

14

* @param rootNode - Optional root DOM node (defaults to document.body)

15

*/

16

function applyBindings(viewModel: any, rootNode?: Node): void;

17

18

/**

19

* Apply bindings to descendant nodes only

20

* @param viewModel - The view model object

21

* @param rootNode - Root DOM node

22

*/

23

function applyBindingsToDescendants(viewModel: any, rootNode: Node): void;

24

25

/**

26

* Apply bindings to a specific DOM node

27

* @param node - Target DOM node

28

* @param bindings - Binding specifications object

29

* @param viewModel - The view model object

30

*/

31

function applyBindingsToNode(node: Node, bindings: object, viewModel: any): void;

32

33

/**

34

* Apply binding accessors to a specific DOM node

35

* @param node - Target DOM node

36

* @param bindingAccessors - Binding accessor functions

37

* @param viewModel - The view model object

38

*/

39

function applyBindingAccessorsToNode(node: Node, bindingAccessors: BindingAccessors, viewModel: any): void;

40

```

41

42

**Usage Examples:**

43

44

```javascript

45

import ko from "knockout";

46

47

// Basic binding application

48

function ViewModel() {

49

this.message = ko.observable("Hello World");

50

}

51

52

ko.applyBindings(new ViewModel());

53

54

// Binding to specific element

55

const element = document.getElementById("myDiv");

56

ko.applyBindings(new ViewModel(), element);

57

58

// Programmatic binding

59

const node = document.getElementById("target");

60

ko.applyBindingsToNode(node, {

61

text: "message",

62

click: "handleClick"

63

}, new ViewModel());

64

```

65

66

### Context Access

67

68

Functions to access binding context and data from DOM nodes.

69

70

```javascript { .api }

71

/**

72

* Get the binding context for a DOM node

73

* @param node - DOM node

74

* @returns Binding context or undefined

75

*/

76

function contextFor(node: Node): BindingContext | undefined;

77

78

/**

79

* Get the data object for a DOM node

80

* @param node - DOM node

81

* @returns Data object or undefined

82

*/

83

function dataFor(node: Node): any;

84

```

85

86

**Usage Examples:**

87

88

```javascript

89

import ko from "knockout";

90

91

const element = document.getElementById("bound-element");

92

const context = ko.contextFor(element);

93

const data = ko.dataFor(element);

94

95

console.log(context.$data); // View model data

96

console.log(data); // Same as context.$data

97

```

98

99

### Binding Context

100

101

Object that provides context information available in binding expressions.

102

103

```typescript { .api }

104

interface BindingContext<T = any> {

105

/** The current data object */

106

$data: T;

107

/** The root view model */

108

$root: any;

109

/** The parent data object */

110

$parent?: any;

111

/** Array of all parent data objects */

112

$parents: any[];

113

/** Observable index for items in foreach binding */

114

$index?: Observable<number>;

115

/** Reference to parent binding context */

116

$parentContext?: BindingContext<any>;

117

/** Current component instance (if inside component) */

118

$component?: any;

119

/** Reference to ko object */

120

ko: any;

121

122

/** Create an extended context with additional properties */

123

extend(properties: object): BindingContext<T>;

124

extend(properties: (self: BindingContext<T>) => object): BindingContext<T>;

125

126

/** Create a child context for nested data */

127

createChildContext<U>(

128

dataItem: U | Observable<U>,

129

dataItemAlias?: string,

130

extendCallback?: (context: BindingContext<U>) => void

131

): BindingContext<U>;

132

}

133

```

134

135

### Binding Handler Registry

136

137

Registry and access for binding handlers.

138

139

```javascript { .api }

140

/**

141

* Registry of all binding handlers

142

*/

143

const bindingHandlers: BindingHandlers;

144

145

/**

146

* Get a specific binding handler

147

* @param name - Binding handler name

148

* @returns Binding handler or undefined

149

*/

150

function getBindingHandler(name: string): BindingHandler | undefined;

151

```

152

153

```typescript { .api }

154

interface BindingHandler<T = any> {

155

/** Initialize the binding (called once) */

156

init?(

157

element: any,

158

valueAccessor: () => T,

159

allBindings: AllBindings,

160

viewModel: any,

161

bindingContext: BindingContext

162

): void | { controlsDescendantBindings: boolean };

163

164

/** Update the binding (called when dependencies change) */

165

update?(

166

element: any,

167

valueAccessor: () => T,

168

allBindings: AllBindings,

169

viewModel: any,

170

bindingContext: BindingContext

171

): void;

172

173

/** Array of binding names that must be processed after this one */

174

after?: string[];

175

176

/** Preprocess binding value before parsing */

177

preprocess?(

178

value: string | undefined,

179

name: string,

180

addBinding: (name: string, value: any) => void

181

): string | undefined | void;

182

}

183

184

interface AllBindings {

185

/** Get all bindings as object */

186

(): any;

187

/** Get specific binding value */

188

get(name: string): any;

189

get<T>(name: string): T;

190

/** Check if binding exists */

191

has(name: string): boolean;

192

}

193

194

interface BindingAccessors {

195

[name: string]: () => any;

196

}

197

```

198

199

### Text and Appearance Bindings

200

201

Bindings that control element text content, visibility, and styling.

202

203

```typescript { .api }

204

interface BindingHandlers {

205

/** Set element text content */

206

text: {

207

update(element: Node, valueAccessor: () => string): void;

208

};

209

210

/** Set element HTML content */

211

html: {

212

update(element: Node, valueAccessor: () => string): void;

213

};

214

215

/** Control element visibility */

216

visible: {

217

update(element: HTMLElement, valueAccessor: () => any): void;

218

};

219

220

/** Control element visibility (inverse of visible) */

221

hidden: {

222

update(element: HTMLElement, valueAccessor: () => any): void;

223

};

224

225

/** Set CSS class name */

226

class: {

227

update(element: HTMLElement, valueAccessor: () => string): void;

228

};

229

230

/** Set CSS classes based on object properties */

231

css: {

232

update(element: HTMLElement, valueAccessor: () => object | string): void;

233

};

234

235

/** Set inline styles */

236

style: {

237

update(element: HTMLElement, valueAccessor: () => object): void;

238

};

239

240

/** Set element attributes */

241

attr: {

242

update(element: HTMLElement, valueAccessor: () => object): void;

243

};

244

}

245

```

246

247

**Usage Examples:**

248

249

```html

250

<!-- Text and HTML content -->

251

<span data-bind="text: message"></span>

252

<div data-bind="html: htmlContent"></div>

253

254

<!-- Visibility -->

255

<div data-bind="visible: isVisible">Visible when true</div>

256

<div data-bind="hidden: isHidden">Hidden when true</div>

257

258

<!-- CSS classes and styles -->

259

<div data-bind="css: { active: isActive, disabled: !isEnabled }"></div>

260

<div data-bind="style: { color: textColor, fontSize: fontSize() + 'px' }"></div>

261

262

<!-- Attributes -->

263

<img data-bind="attr: { src: imageUrl, alt: imageDescription }" />

264

```

265

266

### Control Flow Bindings

267

268

Bindings that control conditional rendering and iteration.

269

270

```typescript { .api }

271

interface BindingHandlers {

272

/** Render template for each array item */

273

foreach: {

274

init(

275

element: Node,

276

valueAccessor: () => any[] | Observable<any[]>,

277

allBindings: AllBindings,

278

viewModel: any,

279

bindingContext: BindingContext

280

): { controlsDescendantBindings: boolean };

281

};

282

283

/** Conditionally include content */

284

if: {

285

init(

286

element: Node,

287

valueAccessor: () => any,

288

allBindings: AllBindings,

289

viewModel: any,

290

bindingContext: BindingContext

291

): { controlsDescendantBindings: boolean };

292

};

293

294

/** Conditionally exclude content */

295

ifnot: {

296

init(

297

element: Node,

298

valueAccessor: () => any,

299

allBindings: AllBindings,

300

viewModel: any,

301

bindingContext: BindingContext

302

): { controlsDescendantBindings: boolean };

303

};

304

305

/** Change binding context */

306

with: {

307

init(

308

element: Node,

309

valueAccessor: () => any,

310

allBindings: AllBindings,

311

viewModel: any,

312

bindingContext: BindingContext

313

): { controlsDescendantBindings: boolean };

314

};

315

316

/** Create local variable bindings */

317

let: {

318

init(

319

element: Node,

320

valueAccessor: () => object,

321

allBindings: AllBindings,

322

viewModel: any,

323

bindingContext: BindingContext

324

): { controlsDescendantBindings: boolean };

325

};

326

327

/** Alias for 'with' binding */

328

using: {

329

init(

330

element: Node,

331

valueAccessor: () => any,

332

allBindings: AllBindings,

333

viewModel: any,

334

bindingContext: BindingContext

335

): { controlsDescendantBindings: boolean };

336

};

337

}

338

```

339

340

**Usage Examples:**

341

342

```html

343

<!-- Foreach binding -->

344

<ul data-bind="foreach: items">

345

<li data-bind="text: $data"></li>

346

</ul>

347

348

<div data-bind="foreach: { data: people, as: 'person' }">

349

<p>Name: <span data-bind="text: person.name"></span></p>

350

<p>Index: <span data-bind="text: $index"></span></p>

351

</div>

352

353

<!-- Conditional bindings -->

354

<div data-bind="if: showDetails">

355

<p>Details content here</p>

356

</div>

357

358

<div data-bind="ifnot: isLoading">

359

<p>Content loaded</p>

360

</div>

361

362

<!-- Context binding -->

363

<div data-bind="with: selectedUser">

364

<p>Name: <span data-bind="text: name"></span></p>

365

<p>Email: <span data-bind="text: email"></span></p>

366

</div>

367

368

<!-- Local variables -->

369

<div data-bind="let: { fullName: firstName() + ' ' + lastName() }">

370

<p data-bind="text: fullName"></p>

371

</div>

372

```

373

374

### Form Field Bindings

375

376

Bindings for form elements and user interaction.

377

378

```typescript { .api }

379

interface BindingHandlers {

380

/** Two-way binding for form field values */

381

value: {

382

init(element: HTMLElement, valueAccessor: () => any, allBindings: AllBindings): void;

383

update(element: HTMLElement, valueAccessor: () => any, allBindings: AllBindings): void;

384

after: string[];

385

};

386

387

/** Two-way binding for text input with immediate updates */

388

textInput: {

389

init(element: HTMLElement, valueAccessor: () => Observable<string>, allBindings: AllBindings): void;

390

};

391

392

/** Handle click events */

393

click: {

394

init(element: HTMLElement, valueAccessor: () => Function, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void;

395

};

396

397

/** Handle multiple events */

398

event: {

399

init(element: HTMLElement, valueAccessor: () => object, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void;

400

};

401

402

/** Handle form submission */

403

submit: {

404

init(element: HTMLElement, valueAccessor: () => Function, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void;

405

};

406

407

/** Control element enabled state */

408

enable: {

409

update(element: HTMLElement, valueAccessor: () => any): void;

410

};

411

412

/** Control element disabled state */

413

disable: {

414

update(element: HTMLElement, valueAccessor: () => any): void;

415

};

416

417

/** Two-way binding for checkbox/radio checked state */

418

checked: {

419

init(element: HTMLElement, valueAccessor: () => any, allBindings: AllBindings): void;

420

after: string[];

421

};

422

423

/** Set value for checked radio button/checkbox */

424

checkedValue: {

425

update(element: HTMLElement, valueAccessor: () => any): void;

426

};

427

428

/** Two-way binding for focus state */

429

hasfocus: {

430

init(element: HTMLElement, valueAccessor: () => Observable<boolean>, allBindings: AllBindings): void;

431

update(element: HTMLElement, valueAccessor: () => Observable<boolean>): void;

432

};

433

434

/** Populate select element options */

435

options: {

436

init(element: HTMLElement): { controlsDescendantBindings: boolean };

437

update(element: HTMLElement, valueAccessor: () => any[], allBindings: AllBindings): void;

438

};

439

440

/** Two-way binding for multi-select selected options */

441

selectedOptions: {

442

init(element: HTMLElement, valueAccessor: () => Observable<any[]>, allBindings: AllBindings): void;

443

update(element: HTMLElement, valueAccessor: () => Observable<any[]>): void;

444

after: string[];

445

};

446

447

/** Generate unique name attribute */

448

uniqueName: {

449

init(element: HTMLElement, valueAccessor: () => boolean): void;

450

};

451

}

452

```

453

454

**Usage Examples:**

455

456

```html

457

<!-- Form field bindings -->

458

<input data-bind="value: userName" />

459

<input data-bind="textInput: searchTerm" />

460

<textarea data-bind="value: description"></textarea>

461

462

<!-- Event bindings -->

463

<button data-bind="click: handleClick">Click Me</button>

464

<button data-bind="event: { mouseover: onMouseOver, mouseout: onMouseOut }">Hover</button>

465

<form data-bind="submit: handleSubmit">

466

<input type="submit" value="Submit" />

467

</form>

468

469

<!-- Enable/disable -->

470

<button data-bind="enable: canSubmit">Submit</button>

471

<input data-bind="disable: isReadOnly" />

472

473

<!-- Checkboxes and radio buttons -->

474

<input type="checkbox" data-bind="checked: isSelected" />

475

<input type="radio" name="color" value="red" data-bind="checked: selectedColor, checkedValue: 'red'" />

476

477

<!-- Focus binding -->

478

<input data-bind="hasfocus: isSearchFocused" />

479

480

<!-- Select options -->

481

<select data-bind="options: availableCountries, value: selectedCountry, optionsText: 'name', optionsValue: 'id'"></select>

482

483

<!-- Multi-select -->

484

<select multiple data-bind="options: availableItems, selectedOptions: selectedItems"></select>

485

```

486

487

### Template and Component Bindings

488

489

Bindings for rendering templates and components.

490

491

```typescript { .api }

492

interface BindingHandlers {

493

/** Render templates with data */

494

template: {

495

init(element: Node, valueAccessor: () => string | TemplateBindingOptions): { controlsDescendantBindings: boolean };

496

update(element: Node, valueAccessor: () => string | TemplateBindingOptions, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): void;

497

};

498

499

/** Render registered components */

500

component: {

501

init(element: Node, valueAccessor: () => { name: string; params?: any }, allBindings: AllBindings, viewModel: any, bindingContext: BindingContext): { controlsDescendantBindings: boolean };

502

};

503

}

504

505

interface TemplateBindingOptions {

506

name?: string | (() => string);

507

data?: any;

508

if?: boolean;

509

ifnot?: boolean;

510

foreach?: any[];

511

as?: string;

512

afterRender?: (elements: Node[], data: any) => void;

513

}

514

```

515

516

**Usage Examples:**

517

518

```html

519

<!-- Template binding -->

520

<div data-bind="template: 'user-template'"></div>

521

<div data-bind="template: { name: 'item-template', data: selectedItem }"></div>

522

<div data-bind="template: { name: 'list-template', foreach: items }"></div>

523

524

<!-- Component binding -->

525

<div data-bind="component: 'user-profile'"></div>

526

<div data-bind="component: { name: 'user-editor', params: { user: selectedUser } }"></div>

527

528

<!-- Template definitions -->

529

<script type="text/html" id="user-template">

530

<p>Name: <span data-bind="text: name"></span></p>

531

<p>Email: <span data-bind="text: email"></span></p>

532

</script>

533

```

534

535

### Custom Binding Creation

536

537

Creating custom binding handlers for specialized functionality.

538

539

```javascript { .api }

540

/**

541

* Example of creating a custom binding handler

542

*/

543

ko.bindingHandlers.customBinding = {

544

init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {

545

// Initialize binding - called once when binding is first applied

546

const value = ko.utils.unwrapObservable(valueAccessor());

547

// Setup event handlers, initial state, etc.

548

549

// Optionally return { controlsDescendantBindings: true } to prevent

550

// descendant bindings from being applied automatically

551

},

552

553

update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {

554

// Update binding - called whenever dependencies change

555

const value = ko.utils.unwrapObservable(valueAccessor());

556

// Update element based on new value

557

}

558

};

559

```

560

561

**Usage Example:**

562

563

```javascript

564

// Custom binding for setting element color

565

ko.bindingHandlers.color = {

566

update: function(element, valueAccessor) {

567

const color = ko.utils.unwrapObservable(valueAccessor());

568

element.style.color = color;

569

}

570

};

571

572

// Usage in HTML

573

// <span data-bind="color: textColor">Colored text</span>

574

```

575

576

### Virtual Elements

577

578

Virtual elements enable data binding on comment-based markup for cases where you cannot add HTML elements. They provide DOM manipulation functions that work with both regular elements and comment-based virtual elements.

579

580

```javascript { .api }

581

/**

582

* Configuration for which bindings are allowed on virtual elements

583

*/

584

const virtualElements: {

585

allowedBindings: VirtualElementsAllowedBindings;

586

587

/** Get child nodes of an element or virtual element */

588

childNodes(node: Node): Node[];

589

590

/** Clear all child nodes from an element or virtual element */

591

emptyNode(node: Node): void;

592

593

/** Get first child of an element or virtual element */

594

firstChild(node: Node): Node;

595

596

/** Insert a node after another node in virtual element context */

597

insertAfter(node: Node, nodeToInsert: Node, insertAfterNode: Node): void;

598

599

/** Get next sibling of a node in virtual element context */

600

nextSibling(node: Node): Node;

601

602

/** Prepend a node to an element or virtual element */

603

prepend(node: Node, nodeToPrepend: Node): void;

604

605

/** Set child nodes of an element or virtual element */

606

setDomNodeChildren(node: Node, childNodes: Node[]): void;

607

};

608

```

609

610

```typescript { .api }

611

interface VirtualElementsAllowedBindings {

612

[bindingName: string]: boolean;

613

}

614

```

615

616

**Usage Examples:**

617

618

```html

619

<!-- Virtual element using comment syntax -->

620

<!-- ko if: showMessage -->

621

<p data-bind="text: message"></p>

622

<!-- /ko -->

623

624

<!-- Virtual foreach -->

625

<!-- ko foreach: items -->

626

<div data-bind="text: name"></div>

627

<!-- /ko -->

628

629

<!-- Virtual with binding -->

630

<!-- ko with: selectedItem -->

631

<div data-bind="text: title"></div>

632

<div data-bind="text: description"></div>

633

<!-- /ko -->

634

```

635

636

```javascript

637

import ko from "knockout";

638

639

// Allow custom binding on virtual elements

640

ko.virtualElements.allowedBindings.myCustomBinding = true;

641

642

// Use virtual element functions

643

const virtualStartComment = document.createComment("ko if: true");

644

const children = ko.virtualElements.childNodes(virtualStartComment);

645

```

646

647

### Binding Provider

648

649

The binding provider system controls how Knockout discovers and processes data bindings in the DOM. This allows customization of binding syntax and preprocessing.

650

651

```javascript { .api }

652

/**

653

* Default binding provider class for processing data-bind attributes

654

*/

655

class bindingProvider implements IBindingProvider {

656

/** Check if a node has bindings */

657

nodeHasBindings(node: Node): boolean;

658

659

/** Get binding object from node */

660

getBindings(node: Node, bindingContext: BindingContext): object;

661

662

/** Get binding accessor functions from node */

663

getBindingAccessors(node: Node, bindingContext: BindingContext): BindingAccessors;

664

665

/** Get raw binding string from node */

666

getBindingsString(node: Node, bindingContext?: BindingContext): string;

667

668

/** Parse binding string into binding object or accessors */

669

parseBindingsString(bindingsString: string, bindingContext: BindingContext, node: Node): object;

670

parseBindingsString(bindingsString: string, bindingContext: BindingContext, node: Node, options: BindingOptions): object | BindingAccessors;

671

672

/** Static reference to current binding provider instance */

673

static instance: IBindingProvider;

674

}

675

```

676

677

```typescript { .api }

678

interface IBindingProvider {

679

/** Check if node has bindings to process */

680

nodeHasBindings(node: Node): boolean;

681

682

/** Get bindings for a node (optional method) */

683

getBindings?(node: Node, bindingContext: BindingContext): object;

684

685

/** Get binding accessor functions for a node */

686

getBindingAccessors(node: Node, bindingContext: BindingContext): BindingAccessors;

687

688

/** Preprocess a node before binding (optional method) */

689

preprocessNode?(node: Node): Node[] | undefined;

690

}

691

692

interface BindingOptions {

693

/** Return accessor functions instead of values */

694

valueAccessors?: boolean;

695

/** Include binding parameters */

696

bindingParams?: boolean;

697

}

698

```

699

700

**Usage Examples:**

701

702

```javascript

703

import ko from "knockout";

704

705

// Custom binding provider

706

class MyBindingProvider {

707

nodeHasBindings(node) {

708

// Custom logic to detect bindings

709

return node.hasAttribute('my-bind');

710

}

711

712

getBindingAccessors(node, bindingContext) {

713

const bindingString = node.getAttribute('my-bind');

714

// Parse custom syntax and return accessors

715

return ko.bindingProvider.prototype.parseBindingsString(

716

bindingString, bindingContext, node

717

);

718

}

719

}

720

721

// Replace default binding provider

722

ko.bindingProvider.instance = new MyBindingProvider();

723

724

// Access current binding provider

725

const provider = ko.bindingProvider.instance;

726

```

727

728

### Expression Rewriting

729

730

System for preprocessing and rewriting binding expressions before evaluation.

731

732

```javascript { .api }

733

/**

734

* Expression rewriting utilities

735

*/

736

const expressionRewriting: {

737

/** Validators for binding rewrite operations */

738

bindingRewriteValidators: any[];

739

740

/** Parse object literal string into key-value pairs */

741

parseObjectLiteral(objectLiteralString: string): KeyValue[];

742

743

/** Preprocess binding string with options */

744

preProcessBindings(bindingsString: string, bindingOptions?: BindingOptions): string;

745

preProcessBindings(keyValueArray: KeyValue[], bindingOptions?: BindingOptions): string;

746

747

/** Internal two-way binding configuration */

748

_twoWayBindings: TwoWayBindings;

749

};

750

```

751

752

```typescript { .api }

753

interface KeyValue {

754

key?: string;

755

value?: string;

756

unknown?: string;

757

}

758

759

interface TwoWayBindings {

760

[bindingName: string]: boolean | string;

761

}

762

```

763

764

**Usage Examples:**

765

766

```javascript

767

import ko from "knockout";

768

769

// Parse object literal from binding string

770

const bindings = ko.expressionRewriting.parseObjectLiteral("text: name, click: save");

771

console.log(bindings); // [{ key: "text", value: "name" }, { key: "click", value: "save" }]

772

773

// Preprocess bindings with options

774

const processed = ko.expressionRewriting.preProcessBindings(

775

"value: userName",

776

{ valueAccessors: true }

777

);

778

```