0
# Utility Functions
1
2
Comprehensive utility library providing array manipulation, DOM utilities, data conversion, and cross-browser compatibility functions. These utilities are available under the `ko.utils` namespace and provide foundational functionality used throughout Knockout.js.
3
4
## Capabilities
5
6
### Array Utilities
7
8
Utility functions for array manipulation and iteration.
9
10
```javascript { .api }
11
/**
12
* Iterate over array elements
13
* @param array - Array to iterate over
14
* @param action - Function called for each element
15
* @param actionOwner - Optional 'this' context for action
16
*/
17
function arrayForEach<T>(
18
array: T[],
19
action: (item: T, index: number) => void,
20
actionOwner?: any
21
): void;
22
23
/**
24
* Find first element matching predicate
25
* @param array - Array to search
26
* @param predicate - Test function
27
* @param predicateOwner - Optional 'this' context for predicate
28
* @returns First matching element or undefined
29
*/
30
function arrayFirst<T>(
31
array: T[],
32
predicate: (item: T, index: number) => boolean,
33
predicateOwner?: any
34
): T | undefined;
35
36
/**
37
* Filter array elements
38
* @param array - Array to filter
39
* @param predicate - Test function
40
* @param predicateOwner - Optional 'this' context for predicate
41
* @returns New array with matching elements
42
*/
43
function arrayFilter<T>(
44
array: T[],
45
predicate: (item: T, index: number) => boolean,
46
predicateOwner?: any
47
): T[];
48
49
/**
50
* Transform array elements
51
* @param array - Array to transform
52
* @param mapping - Transform function
53
* @param mappingOwner - Optional 'this' context for mapping
54
* @returns New array with transformed elements
55
*/
56
function arrayMap<T, U>(
57
array: T[],
58
mapping: (item: T, index: number) => U,
59
mappingOwner?: any
60
): U[];
61
62
/**
63
* Find index of element in array
64
* @param array - Array to search
65
* @param item - Item to find
66
* @returns Index of item or -1 if not found
67
*/
68
function arrayIndexOf<T>(array: T[], item: T): number;
69
70
/**
71
* Add all elements from source array to target array
72
* @param array - Target array to modify
73
* @param valuesToPush - Elements to add
74
* @returns Modified target array
75
*/
76
function arrayPushAll<T>(array: T[], valuesToPush: T[]): T[];
77
78
/**
79
* Remove specific item from array
80
* @param array - Array to modify
81
* @param itemToRemove - Item to remove
82
*/
83
function arrayRemoveItem<T>(array: T[], itemToRemove: T): void;
84
85
/**
86
* Get unique values from array
87
* @param array - Source array
88
* @returns New array with unique values
89
*/
90
function arrayGetDistinctValues<T>(array: T[]): T[];
91
92
/**
93
* Conditionally add or remove item from array
94
* @param array - Array to modify
95
* @param value - Value to add/remove
96
* @param included - Whether to include (true) or exclude (false)
97
* @returns Modified array
98
*/
99
function addOrRemoveItem<T>(array: T[], value: T, included?: boolean): T[];
100
```
101
102
**Usage Examples:**
103
104
```javascript
105
import ko from "knockout";
106
107
const numbers = [1, 2, 3, 4, 5];
108
const people = [
109
{ name: "Alice", age: 25 },
110
{ name: "Bob", age: 30 },
111
{ name: "Charlie", age: 35 }
112
];
113
114
// Array iteration
115
ko.utils.arrayForEach(numbers, (num, index) => {
116
console.log(`${index}: ${num}`);
117
});
118
119
// Finding elements
120
const firstAdult = ko.utils.arrayFirst(people, person => person.age >= 18);
121
console.log(firstAdult); // { name: "Alice", age: 25 }
122
123
// Filtering and mapping
124
const adults = ko.utils.arrayFilter(people, person => person.age >= 18);
125
const names = ko.utils.arrayMap(people, person => person.name);
126
127
// Array manipulation
128
const fruits = ["apple", "banana"];
129
ko.utils.arrayPushAll(fruits, ["orange", "grape"]);
130
console.log(fruits); // ["apple", "banana", "orange", "grape"]
131
```
132
133
### Object Utilities
134
135
Utility functions for object manipulation and property iteration.
136
137
```javascript { .api }
138
/**
139
* Extend target object with properties from source object
140
* @param target - Object to extend
141
* @param source - Source object
142
* @returns Extended target object
143
*/
144
function extend<T, U>(target: T, source: U): T & U;
145
146
/**
147
* Iterate over object properties
148
* @param obj - Object to iterate over
149
* @param action - Function called for each property
150
*/
151
function objectForEach(obj: object, action: (key: string, value: any) => void): void;
152
function objectForEach<T>(obj: { [key: string]: T }, action: (key: string, value: T) => void): void;
153
154
/**
155
* Transform object properties
156
* @param obj - Object to transform
157
* @param mapping - Transform function
158
* @param mappingOwner - Optional 'this' context for mapping
159
* @returns New object with transformed values
160
*/
161
function objectMap<T, U>(
162
obj: { [key: string]: T },
163
mapping: (value: T, key: string) => U,
164
mappingOwner?: any
165
): { [key: string]: U };
166
```
167
168
**Usage Examples:**
169
170
```javascript
171
import ko from "knockout";
172
173
// Object extension
174
const target = { name: "John" };
175
const source = { age: 30, city: "New York" };
176
const extended = ko.utils.extend(target, source);
177
// extended: { name: "John", age: 30, city: "New York" }
178
179
// Object iteration
180
const person = { name: "Alice", age: 25, city: "Boston" };
181
ko.utils.objectForEach(person, (key, value) => {
182
console.log(`${key}: ${value}`);
183
});
184
185
// Object mapping
186
const scores = { math: 85, english: 92, science: 78 };
187
const grades = ko.utils.objectMap(scores, score => {
188
return score >= 90 ? "A" : score >= 80 ? "B" : "C";
189
});
190
// grades: { math: "B", english: "A", science: "C" }
191
```
192
193
### Observable Utilities
194
195
Utility functions for working with observable values.
196
197
```javascript { .api }
198
/**
199
* Unwrap observable value (same as ko.unwrap)
200
* @param value - Observable or regular value
201
* @returns Unwrapped value
202
*/
203
function unwrapObservable<T>(value: T | Observable<T>): T;
204
205
/**
206
* Peek at observable value without creating dependency
207
* @param value - Observable or regular value
208
* @returns Peeked value
209
*/
210
function peekObservable<T>(value: T | Observable<T>): T;
211
```
212
213
**Usage Examples:**
214
215
```javascript
216
import ko from "knockout";
217
218
const observableValue = ko.observable("hello");
219
const regularValue = "world";
220
221
// Unwrap values
222
const unwrapped1 = ko.utils.unwrapObservable(observableValue); // "hello"
223
const unwrapped2 = ko.utils.unwrapObservable(regularValue); // "world"
224
225
// Peek without creating dependency
226
const peeked = ko.utils.peekObservable(observableValue); // "hello"
227
```
228
229
### DOM Utilities
230
231
Utility functions for DOM manipulation and HTML processing.
232
233
```javascript { .api }
234
/**
235
* Parse HTML string into DOM nodes
236
* @param html - HTML string to parse
237
* @param documentContext - Optional document context
238
* @returns Array of DOM nodes
239
*/
240
function parseHtmlFragment(html: string, documentContext?: Document): Node[];
241
242
/**
243
* Set HTML content of element
244
* @param node - Target DOM node
245
* @param html - HTML content to set
246
*/
247
function setHtml(node: Node, html: string): void;
248
249
/**
250
* Trigger DOM event on element
251
* @param element - Target element
252
* @param eventType - Event type (e.g., "click", "change")
253
*/
254
function triggerEvent(element: Element, eventType: string): void;
255
256
/**
257
* Register event handler on element
258
* @param element - Target element
259
* @param eventType - Event type
260
* @param handler - Event handler function
261
*/
262
function registerEventHandler(element: Element, eventType: string, handler: EventListener): void;
263
264
/**
265
* Toggle CSS class on DOM node
266
* @param node - Target element
267
* @param className - CSS class name
268
* @param shouldHaveClass - Whether element should have the class
269
*/
270
function toggleDomNodeCssClass(node: Element, className: string, shouldHaveClass?: boolean): void;
271
272
/**
273
* Set text content of node
274
* @param element - Target node
275
* @param textContent - Text content to set
276
*/
277
function setTextContent(element: Node, textContent: string): void;
278
```
279
280
**Usage Examples:**
281
282
```javascript
283
import ko from "knockout";
284
285
// Parse HTML
286
const htmlString = "<div><p>Hello</p><p>World</p></div>";
287
const nodes = ko.utils.parseHtmlFragment(htmlString);
288
289
// Set HTML content
290
const container = document.getElementById("container");
291
ko.utils.setHtml(container, "<strong>Bold text</strong>");
292
293
// Event handling
294
const button = document.getElementById("myButton");
295
ko.utils.registerEventHandler(button, "click", (event) => {
296
console.log("Button clicked!");
297
});
298
299
// Trigger events
300
ko.utils.triggerEvent(button, "click");
301
302
// CSS class manipulation
303
const element = document.getElementById("myElement");
304
ko.utils.toggleDomNodeCssClass(element, "active", true); // Add class
305
ko.utils.toggleDomNodeCssClass(element, "active", false); // Remove class
306
ko.utils.toggleDomNodeCssClass(element, "active"); // Toggle class
307
```
308
309
### Data Utilities
310
311
Utility functions for JSON parsing, stringification, and form data handling.
312
313
```javascript { .api }
314
/**
315
* Parse JSON string safely
316
* @param jsonString - JSON string to parse
317
* @returns Parsed object or null if invalid
318
*/
319
function parseJson(jsonString: string): any;
320
function parseJson<T>(jsonString: string): T;
321
322
/**
323
* Convert object to JSON string
324
* @param data - Data to stringify
325
* @param replacer - Optional replacer function
326
* @param space - Optional spacing
327
* @returns JSON string
328
*/
329
function stringifyJson(data: any, replacer?: Function, space?: string | number): string;
330
331
/**
332
* Post JSON data to URL
333
* @param urlOrForm - URL string or form element
334
* @param data - Data to post
335
* @param options - Optional posting options
336
*/
337
function postJson(urlOrForm: string | HTMLFormElement, data: any, options?: PostJsonOptions): void;
338
339
/**
340
* Get form field elements by name or pattern
341
* @param form - Form element
342
* @param fieldName - Field name or RegExp pattern
343
* @returns Array of matching form elements
344
*/
345
function getFormFields(form: HTMLFormElement, fieldName: string | RegExp): HTMLElement[];
346
```
347
348
```typescript { .api }
349
interface PostJsonOptions {
350
params?: object;
351
includeFields?: string[];
352
submitter?: (form: HTMLFormElement) => void;
353
}
354
```
355
356
**Usage Examples:**
357
358
```javascript
359
import ko from "knockout";
360
361
// JSON operations
362
const jsonString = '{"name": "John", "age": 30}';
363
const parsed = ko.utils.parseJson(jsonString);
364
console.log(parsed); // { name: "John", age: 30 }
365
366
const data = { message: "Hello World", timestamp: Date.now() };
367
const jsonStr = ko.utils.stringifyJson(data);
368
369
// Post JSON data
370
ko.utils.postJson("/api/users", {
371
name: "Alice",
372
email: "alice@example.com"
373
});
374
375
// Form field handling
376
const form = document.getElementById("myForm");
377
const nameFields = ko.utils.getFormFields(form, "name");
378
const allFields = ko.utils.getFormFields(form, /.*input.*/);
379
```
380
381
### Numeric Utilities
382
383
Utility functions for generating numeric ranges.
384
385
```javascript { .api }
386
/**
387
* Generate range of numbers
388
* @param min - Minimum value (can be observable)
389
* @param max - Maximum value (can be observable)
390
* @returns Array of numbers from min to max
391
*/
392
function range(min: number | Observable<number>, max: number | Observable<number>): number[];
393
```
394
395
**Usage Examples:**
396
397
```javascript
398
import ko from "knockout";
399
400
// Static range
401
const numbers = ko.utils.range(1, 5);
402
console.log(numbers); // [1, 2, 3, 4, 5]
403
404
// Observable range
405
const min = ko.observable(10);
406
const max = ko.observable(15);
407
const dynamicRange = ko.utils.range(min, max);
408
console.log(dynamicRange); // [10, 11, 12, 13, 14, 15]
409
```
410
411
### Array Comparison
412
413
Advanced array comparison utilities for detecting changes.
414
415
```javascript { .api }
416
/**
417
* Compare two arrays and return change information
418
* @param oldArray - Original array
419
* @param newArray - New array to compare
420
* @param options - Optional comparison options
421
* @returns Array of change objects
422
*/
423
function compareArrays<T>(
424
oldArray: T[],
425
newArray: T[],
426
options?: CompareArraysOptions
427
): ArrayChange<T>[];
428
```
429
430
```typescript { .api }
431
interface ArrayChange<T> {
432
status: "added" | "deleted" | "retained";
433
value: T;
434
index: number;
435
moved?: number;
436
}
437
438
interface CompareArraysOptions {
439
dontLimitMoves?: boolean;
440
sparse?: boolean;
441
}
442
```
443
444
**Usage Examples:**
445
446
```javascript
447
import ko from "knockout";
448
449
const oldArray = ["a", "b", "c"];
450
const newArray = ["a", "c", "d"];
451
const changes = ko.utils.compareArrays(oldArray, newArray);
452
453
console.log(changes);
454
// [
455
// { status: "retained", value: "a", index: 0 },
456
// { status: "deleted", value: "b", index: 1 },
457
// { status: "retained", value: "c", index: 2 },
458
// { status: "added", value: "d", index: 3 }
459
// ]
460
```
461
462
### DOM Data Storage
463
464
Utility functions for storing and retrieving data associated with DOM nodes.
465
466
```javascript { .api }
467
const domData: {
468
/**
469
* Get data stored on DOM node
470
* @param node - DOM node
471
* @param key - Data key
472
* @returns Stored data or undefined
473
*/
474
get<T>(node: Node, key: string): T | undefined;
475
476
/**
477
* Set data on DOM node
478
* @param node - DOM node
479
* @param key - Data key
480
* @param value - Data value
481
*/
482
set<T>(node: Node, key: string, value: T): void;
483
484
/**
485
* Clear all data from DOM node
486
* @param node - DOM node
487
* @returns True if data was cleared
488
*/
489
clear(node: Node): boolean;
490
};
491
```
492
493
### DOM Node Disposal
494
495
Utility functions for DOM node cleanup and disposal callbacks.
496
497
```javascript { .api }
498
const domNodeDisposal: {
499
/**
500
* Add disposal callback for DOM node
501
* @param node - DOM node
502
* @param callback - Callback to execute when node is disposed
503
*/
504
addDisposeCallback(node: Node, callback: (node: Node) => void): void;
505
506
/**
507
* Remove disposal callback from DOM node
508
* @param node - DOM node
509
* @param callback - Callback to remove
510
*/
511
removeDisposeCallback(node: Node, callback: (node: Node) => void): void;
512
513
/**
514
* Clean external data associated with node
515
* @param node - DOM node
516
*/
517
cleanExternalData(node: Node): void;
518
};
519
```
520
521
### Cross-browser Compatibility
522
523
Built-in fields and utilities for cross-browser form handling.
524
525
```javascript { .api }
526
/**
527
* Array of field names/patterns included in JSON posts
528
*/
529
const fieldsIncludedWithJsonPost: (string | RegExp)[];
530
```
531
532
**Usage Examples:**
533
534
```javascript
535
import ko from "knockout";
536
537
// DOM data storage
538
const element = document.getElementById("myElement");
539
ko.utils.domData.set(element, "userData", { id: 123, name: "Test" });
540
const userData = ko.utils.domData.get(element, "userData");
541
542
// Disposal callbacks
543
ko.utils.domNodeDisposal.addDisposeCallback(element, (node) => {
544
console.log("Element disposed:", node);
545
});
546
547
// Check included fields for form posts
548
console.log(ko.utils.fieldsIncludedWithJsonPost);
549
// ["authenticity_token", /^__RequestVerificationToken(_.*)?$/]
550
```
551
552
### DOM Node Management
553
554
Advanced DOM manipulation functions for managing node lifecycle and cleanup.
555
556
```javascript { .api }
557
/**
558
* Clean up a DOM node and dispose of associated data
559
* @param node - DOM node to clean
560
* @returns The cleaned node (same instance)
561
*/
562
function cleanNode(node: Node): typeof node;
563
564
/**
565
* Remove a DOM node from its parent and clean it up
566
* @param node - DOM node to remove
567
*/
568
function removeNode(node: Node): void;
569
```
570
571
**Usage Examples:**
572
573
```javascript
574
import ko from "knockout";
575
576
// Clean up node before reuse
577
const element = document.getElementById("reusable");
578
ko.cleanNode(element);
579
580
// Remove and clean up node
581
const obsoleteElement = document.getElementById("obsolete");
582
ko.removeNode(obsoleteElement);
583
```
584
585
### Array-DOM Mapping
586
587
Advanced utilities for efficiently mapping arrays to DOM nodes with change tracking and lifecycle hooks.
588
589
```javascript { .api }
590
/**
591
* Map array to DOM nodes with efficient change tracking
592
* @param domNode - Container node for generated nodes
593
* @param array - Source array to map
594
* @param mapping - Function to create nodes for each array item
595
* @param options - Optional mapping behavior configuration
596
* @param callbackAfterAddingNodes - Optional callback after nodes are added
597
*/
598
function setDomNodeChildrenFromArrayMapping<T>(
599
domNode: Node,
600
array: T[],
601
mapping: MappingFunction<T>,
602
options?: MappingOptions<T>,
603
callbackAfterAddingNodes?: MappingAfterAddFunction<T>
604
): void;
605
```
606
607
```typescript { .api }
608
/**
609
* Function that creates DOM nodes for array items
610
*/
611
type MappingFunction<T> = (valueToMap: T, index: number, nodes: Node[]) => Node[];
612
613
/**
614
* Callback executed after nodes are added to DOM
615
*/
616
type MappingAfterAddFunction<T> = (arrayEntry: T, nodes: Node[], index: Observable<number>) => Node[];
617
618
/**
619
* Callback executed during array change lifecycle events
620
*/
621
type MappingHookFunction<T> = (nodes: Node[], index: number, arrayEntry: T) => void;
622
623
/**
624
* Configuration options for array-DOM mapping behavior
625
*/
626
interface MappingOptions<T> {
627
/** Don't limit DOM moves during array reordering */
628
dontLimitMoves?: boolean;
629
/** Called before moving nodes for reordered items */
630
beforeMove?: MappingHookFunction<T>;
631
/** Called before removing nodes for deleted items */
632
beforeRemove?: MappingHookFunction<T>;
633
/** Called after adding nodes for new items */
634
afterAdd?: MappingHookFunction<T>;
635
/** Called after moving nodes for reordered items */
636
afterMove?: MappingHookFunction<T>;
637
/** Called after removing nodes for deleted items */
638
afterRemove?: MappingHookFunction<T>;
639
}
640
```
641
642
**Usage Examples:**
643
644
```javascript
645
import ko from "knockout";
646
647
const container = document.getElementById("list-container");
648
const items = ko.observableArray([
649
{ id: 1, name: "Item 1" },
650
{ id: 2, name: "Item 2" }
651
]);
652
653
// Map array to DOM with lifecycle hooks
654
ko.utils.setDomNodeChildrenFromArrayMapping(
655
container,
656
items(),
657
(item, index, nodes) => {
658
const div = document.createElement("div");
659
div.textContent = item.name;
660
div.setAttribute("data-id", item.id);
661
return [div];
662
},
663
{
664
beforeRemove: (nodes, index, item) => {
665
console.log("Removing item:", item.name);
666
},
667
afterAdd: (nodes, index, item) => {
668
console.log("Added item:", item.name);
669
// Animate new nodes
670
nodes.forEach(node => {
671
node.style.opacity = "0";
672
setTimeout(() => node.style.opacity = "1", 10);
673
});
674
}
675
}
676
);
677
678
// Update array - DOM will be efficiently updated
679
items.push({ id: 3, name: "Item 3" });
680
items.remove(items()[0]);
681
```