JavaScript MVVM library that makes it easier to create rich, responsive UIs with automatic UI synchronization through observable data binding
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
Utility functions for array manipulation and iteration.
/**
* Iterate over array elements
* @param array - Array to iterate over
* @param action - Function called for each element
* @param actionOwner - Optional 'this' context for action
*/
function arrayForEach<T>(
array: T[],
action: (item: T, index: number) => void,
actionOwner?: any
): void;
/**
* Find first element matching predicate
* @param array - Array to search
* @param predicate - Test function
* @param predicateOwner - Optional 'this' context for predicate
* @returns First matching element or undefined
*/
function arrayFirst<T>(
array: T[],
predicate: (item: T, index: number) => boolean,
predicateOwner?: any
): T | undefined;
/**
* Filter array elements
* @param array - Array to filter
* @param predicate - Test function
* @param predicateOwner - Optional 'this' context for predicate
* @returns New array with matching elements
*/
function arrayFilter<T>(
array: T[],
predicate: (item: T, index: number) => boolean,
predicateOwner?: any
): T[];
/**
* Transform array elements
* @param array - Array to transform
* @param mapping - Transform function
* @param mappingOwner - Optional 'this' context for mapping
* @returns New array with transformed elements
*/
function arrayMap<T, U>(
array: T[],
mapping: (item: T, index: number) => U,
mappingOwner?: any
): U[];
/**
* Find index of element in array
* @param array - Array to search
* @param item - Item to find
* @returns Index of item or -1 if not found
*/
function arrayIndexOf<T>(array: T[], item: T): number;
/**
* Add all elements from source array to target array
* @param array - Target array to modify
* @param valuesToPush - Elements to add
* @returns Modified target array
*/
function arrayPushAll<T>(array: T[], valuesToPush: T[]): T[];
/**
* Remove specific item from array
* @param array - Array to modify
* @param itemToRemove - Item to remove
*/
function arrayRemoveItem<T>(array: T[], itemToRemove: T): void;
/**
* Get unique values from array
* @param array - Source array
* @returns New array with unique values
*/
function arrayGetDistinctValues<T>(array: T[]): T[];
/**
* Conditionally add or remove item from array
* @param array - Array to modify
* @param value - Value to add/remove
* @param included - Whether to include (true) or exclude (false)
* @returns Modified array
*/
function addOrRemoveItem<T>(array: T[], value: T, included?: boolean): T[];Usage Examples:
import ko from "knockout";
const numbers = [1, 2, 3, 4, 5];
const people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];
// Array iteration
ko.utils.arrayForEach(numbers, (num, index) => {
console.log(`${index}: ${num}`);
});
// Finding elements
const firstAdult = ko.utils.arrayFirst(people, person => person.age >= 18);
console.log(firstAdult); // { name: "Alice", age: 25 }
// Filtering and mapping
const adults = ko.utils.arrayFilter(people, person => person.age >= 18);
const names = ko.utils.arrayMap(people, person => person.name);
// Array manipulation
const fruits = ["apple", "banana"];
ko.utils.arrayPushAll(fruits, ["orange", "grape"]);
console.log(fruits); // ["apple", "banana", "orange", "grape"]Utility functions for object manipulation and property iteration.
/**
* Extend target object with properties from source object
* @param target - Object to extend
* @param source - Source object
* @returns Extended target object
*/
function extend<T, U>(target: T, source: U): T & U;
/**
* Iterate over object properties
* @param obj - Object to iterate over
* @param action - Function called for each property
*/
function objectForEach(obj: object, action: (key: string, value: any) => void): void;
function objectForEach<T>(obj: { [key: string]: T }, action: (key: string, value: T) => void): void;
/**
* Transform object properties
* @param obj - Object to transform
* @param mapping - Transform function
* @param mappingOwner - Optional 'this' context for mapping
* @returns New object with transformed values
*/
function objectMap<T, U>(
obj: { [key: string]: T },
mapping: (value: T, key: string) => U,
mappingOwner?: any
): { [key: string]: U };Usage Examples:
import ko from "knockout";
// Object extension
const target = { name: "John" };
const source = { age: 30, city: "New York" };
const extended = ko.utils.extend(target, source);
// extended: { name: "John", age: 30, city: "New York" }
// Object iteration
const person = { name: "Alice", age: 25, city: "Boston" };
ko.utils.objectForEach(person, (key, value) => {
console.log(`${key}: ${value}`);
});
// Object mapping
const scores = { math: 85, english: 92, science: 78 };
const grades = ko.utils.objectMap(scores, score => {
return score >= 90 ? "A" : score >= 80 ? "B" : "C";
});
// grades: { math: "B", english: "A", science: "C" }Utility functions for working with observable values.
/**
* Unwrap observable value (same as ko.unwrap)
* @param value - Observable or regular value
* @returns Unwrapped value
*/
function unwrapObservable<T>(value: T | Observable<T>): T;
/**
* Peek at observable value without creating dependency
* @param value - Observable or regular value
* @returns Peeked value
*/
function peekObservable<T>(value: T | Observable<T>): T;Usage Examples:
import ko from "knockout";
const observableValue = ko.observable("hello");
const regularValue = "world";
// Unwrap values
const unwrapped1 = ko.utils.unwrapObservable(observableValue); // "hello"
const unwrapped2 = ko.utils.unwrapObservable(regularValue); // "world"
// Peek without creating dependency
const peeked = ko.utils.peekObservable(observableValue); // "hello"Utility functions for DOM manipulation and HTML processing.
/**
* Parse HTML string into DOM nodes
* @param html - HTML string to parse
* @param documentContext - Optional document context
* @returns Array of DOM nodes
*/
function parseHtmlFragment(html: string, documentContext?: Document): Node[];
/**
* Set HTML content of element
* @param node - Target DOM node
* @param html - HTML content to set
*/
function setHtml(node: Node, html: string): void;
/**
* Trigger DOM event on element
* @param element - Target element
* @param eventType - Event type (e.g., "click", "change")
*/
function triggerEvent(element: Element, eventType: string): void;
/**
* Register event handler on element
* @param element - Target element
* @param eventType - Event type
* @param handler - Event handler function
*/
function registerEventHandler(element: Element, eventType: string, handler: EventListener): void;
/**
* Toggle CSS class on DOM node
* @param node - Target element
* @param className - CSS class name
* @param shouldHaveClass - Whether element should have the class
*/
function toggleDomNodeCssClass(node: Element, className: string, shouldHaveClass?: boolean): void;
/**
* Set text content of node
* @param element - Target node
* @param textContent - Text content to set
*/
function setTextContent(element: Node, textContent: string): void;Usage Examples:
import ko from "knockout";
// Parse HTML
const htmlString = "<div><p>Hello</p><p>World</p></div>";
const nodes = ko.utils.parseHtmlFragment(htmlString);
// Set HTML content
const container = document.getElementById("container");
ko.utils.setHtml(container, "<strong>Bold text</strong>");
// Event handling
const button = document.getElementById("myButton");
ko.utils.registerEventHandler(button, "click", (event) => {
console.log("Button clicked!");
});
// Trigger events
ko.utils.triggerEvent(button, "click");
// CSS class manipulation
const element = document.getElementById("myElement");
ko.utils.toggleDomNodeCssClass(element, "active", true); // Add class
ko.utils.toggleDomNodeCssClass(element, "active", false); // Remove class
ko.utils.toggleDomNodeCssClass(element, "active"); // Toggle classUtility functions for JSON parsing, stringification, and form data handling.
/**
* Parse JSON string safely
* @param jsonString - JSON string to parse
* @returns Parsed object or null if invalid
*/
function parseJson(jsonString: string): any;
function parseJson<T>(jsonString: string): T;
/**
* Convert object to JSON string
* @param data - Data to stringify
* @param replacer - Optional replacer function
* @param space - Optional spacing
* @returns JSON string
*/
function stringifyJson(data: any, replacer?: Function, space?: string | number): string;
/**
* Post JSON data to URL
* @param urlOrForm - URL string or form element
* @param data - Data to post
* @param options - Optional posting options
*/
function postJson(urlOrForm: string | HTMLFormElement, data: any, options?: PostJsonOptions): void;
/**
* Get form field elements by name or pattern
* @param form - Form element
* @param fieldName - Field name or RegExp pattern
* @returns Array of matching form elements
*/
function getFormFields(form: HTMLFormElement, fieldName: string | RegExp): HTMLElement[];interface PostJsonOptions {
params?: object;
includeFields?: string[];
submitter?: (form: HTMLFormElement) => void;
}Usage Examples:
import ko from "knockout";
// JSON operations
const jsonString = '{"name": "John", "age": 30}';
const parsed = ko.utils.parseJson(jsonString);
console.log(parsed); // { name: "John", age: 30 }
const data = { message: "Hello World", timestamp: Date.now() };
const jsonStr = ko.utils.stringifyJson(data);
// Post JSON data
ko.utils.postJson("/api/users", {
name: "Alice",
email: "alice@example.com"
});
// Form field handling
const form = document.getElementById("myForm");
const nameFields = ko.utils.getFormFields(form, "name");
const allFields = ko.utils.getFormFields(form, /.*input.*/);Utility functions for generating numeric ranges.
/**
* Generate range of numbers
* @param min - Minimum value (can be observable)
* @param max - Maximum value (can be observable)
* @returns Array of numbers from min to max
*/
function range(min: number | Observable<number>, max: number | Observable<number>): number[];Usage Examples:
import ko from "knockout";
// Static range
const numbers = ko.utils.range(1, 5);
console.log(numbers); // [1, 2, 3, 4, 5]
// Observable range
const min = ko.observable(10);
const max = ko.observable(15);
const dynamicRange = ko.utils.range(min, max);
console.log(dynamicRange); // [10, 11, 12, 13, 14, 15]Advanced array comparison utilities for detecting changes.
/**
* Compare two arrays and return change information
* @param oldArray - Original array
* @param newArray - New array to compare
* @param options - Optional comparison options
* @returns Array of change objects
*/
function compareArrays<T>(
oldArray: T[],
newArray: T[],
options?: CompareArraysOptions
): ArrayChange<T>[];interface ArrayChange<T> {
status: "added" | "deleted" | "retained";
value: T;
index: number;
moved?: number;
}
interface CompareArraysOptions {
dontLimitMoves?: boolean;
sparse?: boolean;
}Usage Examples:
import ko from "knockout";
const oldArray = ["a", "b", "c"];
const newArray = ["a", "c", "d"];
const changes = ko.utils.compareArrays(oldArray, newArray);
console.log(changes);
// [
// { status: "retained", value: "a", index: 0 },
// { status: "deleted", value: "b", index: 1 },
// { status: "retained", value: "c", index: 2 },
// { status: "added", value: "d", index: 3 }
// ]Utility functions for storing and retrieving data associated with DOM nodes.
const domData: {
/**
* Get data stored on DOM node
* @param node - DOM node
* @param key - Data key
* @returns Stored data or undefined
*/
get<T>(node: Node, key: string): T | undefined;
/**
* Set data on DOM node
* @param node - DOM node
* @param key - Data key
* @param value - Data value
*/
set<T>(node: Node, key: string, value: T): void;
/**
* Clear all data from DOM node
* @param node - DOM node
* @returns True if data was cleared
*/
clear(node: Node): boolean;
};Utility functions for DOM node cleanup and disposal callbacks.
const domNodeDisposal: {
/**
* Add disposal callback for DOM node
* @param node - DOM node
* @param callback - Callback to execute when node is disposed
*/
addDisposeCallback(node: Node, callback: (node: Node) => void): void;
/**
* Remove disposal callback from DOM node
* @param node - DOM node
* @param callback - Callback to remove
*/
removeDisposeCallback(node: Node, callback: (node: Node) => void): void;
/**
* Clean external data associated with node
* @param node - DOM node
*/
cleanExternalData(node: Node): void;
};Built-in fields and utilities for cross-browser form handling.
/**
* Array of field names/patterns included in JSON posts
*/
const fieldsIncludedWithJsonPost: (string | RegExp)[];Usage Examples:
import ko from "knockout";
// DOM data storage
const element = document.getElementById("myElement");
ko.utils.domData.set(element, "userData", { id: 123, name: "Test" });
const userData = ko.utils.domData.get(element, "userData");
// Disposal callbacks
ko.utils.domNodeDisposal.addDisposeCallback(element, (node) => {
console.log("Element disposed:", node);
});
// Check included fields for form posts
console.log(ko.utils.fieldsIncludedWithJsonPost);
// ["authenticity_token", /^__RequestVerificationToken(_.*)?$/]Advanced DOM manipulation functions for managing node lifecycle and cleanup.
/**
* Clean up a DOM node and dispose of associated data
* @param node - DOM node to clean
* @returns The cleaned node (same instance)
*/
function cleanNode(node: Node): typeof node;
/**
* Remove a DOM node from its parent and clean it up
* @param node - DOM node to remove
*/
function removeNode(node: Node): void;Usage Examples:
import ko from "knockout";
// Clean up node before reuse
const element = document.getElementById("reusable");
ko.cleanNode(element);
// Remove and clean up node
const obsoleteElement = document.getElementById("obsolete");
ko.removeNode(obsoleteElement);Advanced utilities for efficiently mapping arrays to DOM nodes with change tracking and lifecycle hooks.
/**
* Map array to DOM nodes with efficient change tracking
* @param domNode - Container node for generated nodes
* @param array - Source array to map
* @param mapping - Function to create nodes for each array item
* @param options - Optional mapping behavior configuration
* @param callbackAfterAddingNodes - Optional callback after nodes are added
*/
function setDomNodeChildrenFromArrayMapping<T>(
domNode: Node,
array: T[],
mapping: MappingFunction<T>,
options?: MappingOptions<T>,
callbackAfterAddingNodes?: MappingAfterAddFunction<T>
): void;/**
* Function that creates DOM nodes for array items
*/
type MappingFunction<T> = (valueToMap: T, index: number, nodes: Node[]) => Node[];
/**
* Callback executed after nodes are added to DOM
*/
type MappingAfterAddFunction<T> = (arrayEntry: T, nodes: Node[], index: Observable<number>) => Node[];
/**
* Callback executed during array change lifecycle events
*/
type MappingHookFunction<T> = (nodes: Node[], index: number, arrayEntry: T) => void;
/**
* Configuration options for array-DOM mapping behavior
*/
interface MappingOptions<T> {
/** Don't limit DOM moves during array reordering */
dontLimitMoves?: boolean;
/** Called before moving nodes for reordered items */
beforeMove?: MappingHookFunction<T>;
/** Called before removing nodes for deleted items */
beforeRemove?: MappingHookFunction<T>;
/** Called after adding nodes for new items */
afterAdd?: MappingHookFunction<T>;
/** Called after moving nodes for reordered items */
afterMove?: MappingHookFunction<T>;
/** Called after removing nodes for deleted items */
afterRemove?: MappingHookFunction<T>;
}Usage Examples:
import ko from "knockout";
const container = document.getElementById("list-container");
const items = ko.observableArray([
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" }
]);
// Map array to DOM with lifecycle hooks
ko.utils.setDomNodeChildrenFromArrayMapping(
container,
items(),
(item, index, nodes) => {
const div = document.createElement("div");
div.textContent = item.name;
div.setAttribute("data-id", item.id);
return [div];
},
{
beforeRemove: (nodes, index, item) => {
console.log("Removing item:", item.name);
},
afterAdd: (nodes, index, item) => {
console.log("Added item:", item.name);
// Animate new nodes
nodes.forEach(node => {
node.style.opacity = "0";
setTimeout(() => node.style.opacity = "1", 10);
});
}
}
);
// Update array - DOM will be efficiently updated
items.push({ id: 3, name: "Item 3" });
items.remove(items()[0]);