diff --git a/Definitions/knockout-2.2.d.ts b/Definitions/knockout-2.2.d.ts
index 639aa4159..cf346a778 100644
--- a/Definitions/knockout-2.2.d.ts
+++ b/Definitions/knockout-2.2.d.ts
@@ -1,6 +1,12 @@
-// Type definitions for Knockout 2.1.0
+// Type definitions for Knockout 2.2
+// Project: http://knockoutjs.com
// https://github.com/borisyankov/DefinitelyTyped
+
+interface KnockoutSubscription {
+ dispose(): void;
+}
+
interface KnockoutObservableArrayFunctions {
// General Array functions
indexOf(searchElement, fromIndex?: number): number;
@@ -26,23 +32,33 @@ interface KnockoutObservableArrayFunctions {
}
interface KnockoutObservableArray extends KnockoutObservableArrayFunctions {
- (): any[];
- (value: any[]): void;
-}
-interface KnockoutObservableArrayStatic {
- (): KnockoutObservableArray;
fn: KnockoutObservableArrayFunctions;
+
+ (): KnockoutObservableArray;
+ (value: any[]): KnockoutObservableArray;
}
interface KnockoutObservable {
+
+ fn;
+
(): any;
(value): void;
- subscribe(func: Function): void;
+ extend(source);
+ subscribe(func: Function): KnockoutSubscription;
}
interface KnockoutComputed extends KnockoutObservable {
+ (): KnockoutComputed;
+ (func: Function, context?: any): KnockoutComputed;
+ (def: KnockoutComputedDefine): KnockoutComputed;
+ (options?: any): KnockoutComputed;
+
+ subscribe(callback: (newValue: number) => void ): KnockoutSubscription;
+ getDependenciesCount(): number;
+ hasWriteFunction(): bool;
}
interface KnockoutComputedDefine {
@@ -50,12 +66,6 @@ interface KnockoutComputedDefine {
write(any);
}
-interface KnockoutComputedStatic {
- (): KnockoutComputed;
- (func: Function): KnockoutComputed;
- (def: KnockoutComputedDefine) : KnockoutComputed;
-}
-
interface KnockoutBindingContext {
$parent: any;
$parents: any[];
@@ -72,55 +82,102 @@ interface KnockoutBindingHandler {
//update(element: any, valueAccessor: any, allBindingsAccessor: any, viewModel: any, bindingContext: KnockoutBindingContext) : void;
init: any;
update: any;
+ options: any;
}
interface KnockoutBindingHandlers {
value: KnockoutBindingHandler;
}
-interface KnockoutStatic {
- utils: KnockoutUtilsStatic;
- bindingHandlers: KnockoutBindingHandlers;
- applyBindings(viewModel, rootNode?);
- computed : KnockoutComputedStatic;
- observableArray: KnockoutObservableArrayStatic;
- observable(intial?): KnockoutObservable;
+interface KnockoutMemoization {
+ memoize(callback);
+ unmemoize(memoId, callbackParams);
+ unmemoizeDomNodeAndDescendants(domNode, extraCallbackParamsArray);
+ parseMemoText(memoText);
}
-interface KnockoutUtilsStatic {
- arrayForEach(array: any[], action);
- arrayIndexOf(array: any[], item);
- arrayFirst(array: any[], predicate, predicateOwner?);
- arrayRemoveItem(array: any[], itemToRemove);
- arrayGetDistinctValues(array: any[]);
- arrayMap(array: any[], mapping);
- arrayFilter(array: any[], predicate);
- arrayPushAll(array: any[], valuesToPush);
+interface KnockoutVirtualElements {
+ allowedBindings;
+ emptyNode;
+ firstChild;
+ insertAfter;
+ nextSibling;
+ prepend;
+ setDomNodeChildren;
+}
+
+interface KnockoutExtenders {
+ throttle(target: any, timeout: number): KnockoutComputed;
+ notify(target: any, notifyWhen: string): any;
+}
+
+interface KnockoutUtils {
+
+ fieldsIncludedWithJsonPost: any[];
+
+ arrayForEach(array: any[], action: (any) => void ): void;
+ arrayIndexOf(array: any[], item: any): number;
+ arrayFirst(array: any[], predicate: (item) => bool, predicateOwner?: any): any;
+ arrayRemoveItem(array: any[], itemToRemove: any): void;
+ arrayGetDistinctValues(array: any[]): any[];
+ arrayMap(array: any[], mapping: (item) => any): any[];
+ arrayFilter(array: any[], predicate: (item) => bool): any[];
+ arrayPushAll(array: any[], valuesToPush: any[]): any[];
+
extend(target, source);
- emptyDomNode(domNode);
- moveCleanedNodesToContainerElement(nodes);
- setDomNodeChildren(domNode, childNodes);
- replaceDomNodes(nodeToReplaceOrNodeArray, newNodesArray);
- setOptionNodeSelectionState(optionNode, isSelected);
- stringTrim(str: string);
- stringTokenize(str: string, delimiter);
- stringStartsWith(str: string, startsWith);
- buildEvalWithinScopeFunction(expression, scopeLevels);
- domNodeIsContainedBy(node, containedByNode);
- domNodeIsAttachedToDocument(node);
- tagNameLower(element);
- registerEventHandler(element, eventType, handler);
- triggerEvent(element, eventType);
- unwrapObservable(value);
- toggleDomNodeCssClass(node, className, shouldHaveClass);
- setTextContent(element, textContent);
+
+ emptyDomNode(domNode): void;
+ moveCleanedNodesToContainerElement(nodes: any[]): HTMLElement;
+ cloneNodes(nodesArray: any[], shouldCleanNodes: bool): any[];
+ setDomNodeChildren(domNode: any, childNodes: any[]): void;
+ replaceDomNodes(nodeToReplaceOrNodeArray: any, newNodesArray: any[]): void;
+ setOptionNodeSelectionState(optionNode: any, isSelected: bool): void;
+ stringTrim(str: string): string;
+ stringTokenize(str: string, delimiter: string): string;
+ stringStartsWith(str: string, startsWith: string): string;
+ domNodeIsContainedBy(node: any, containedByNode: any): bool;
+ domNodeIsAttachedToDocument(node: any): bool;
+ tagNameLower(element: any): string;
+ registerEventHandler(element: any, eventType: any, handler: Function): void;
+ triggerEvent(element: any, eventType: any): void;
+ unwrapObservable(value: any): any;
+ toggleDomNodeCssClass(node: any, className: string, shouldHaveClass: bool): void;
+ setTextContent(element: any, textContent: string): void;
+ setElementName(element: any, name: string): void;
ensureSelectElementIsRenderedCorrectly(selectElement);
- range(min, max);
- makeArray(arrayLikeObject);
- getFormFields(form, fieldName);
- parseJson(jsonString);
- stringifyJson(data, replacer, space);
- postJson(urlOrForm, data, options);
+ forceRefresh(node: any): void;
+ ensureSelectElementIsRenderedCorrectly(selectElement: any): void;
+ range(min: any, max: any): any;
+ makeArray(arrayLikeObject: any): any[];
+ getFormFields(form: any, fieldName: string): any[];
+ parseJson(jsonString: string): any;
+ stringifyJson(data: any, replacer: Function, space: string): string;
+ postJson(urlOrForm: any, data: any, options: any): void;
+
+ domNodeDisposal;
+}
+
+
+interface KnockoutStatic {
+ utils: KnockoutUtils;
+ memoization: KnockoutMemoization;
+ bindingHandlers: KnockoutBindingHandlers;
+
+ computed: KnockoutComputed;
+ observableArray: KnockoutObservableArray;
+ virtualElements: KnockoutVirtualElements;
+ extenders: KnockoutExtenders;
+
+ applyBindings(viewModel: any, rootNode?: any): void;
+ applyBindingsToDescendants(viewModel: any, rootNode: any): void;
+ observable(intial? ): KnockoutObservable;
+ contextFor(node: any): any;
+ isSubscribable(instance: any): bool;
+ subscribable(): void;
+ toJSON(viewModel: any, replacer?: Function, space?: any): string;
+ toJS(viewModel: any): any;
+ isObservable(instance: any): bool;
+ dataFor(node: any): any;
}
declare var ko: KnockoutStatic;
\ No newline at end of file
diff --git a/Tests/knockout-tests.ts b/Tests/knockout-tests.ts
new file mode 100644
index 000000000..a2c7e8d8d
--- /dev/null
+++ b/Tests/knockout-tests.ts
@@ -0,0 +1,517 @@
+///
+///
+
+declare var $;
+
+function test_creatingVMs() {
+ var myViewModel = {
+ personName: ko.observable('Bob'),
+ personAge: ko.observable(123)
+ };
+ ko.applyBindings(myViewModel);
+ ko.applyBindings(myViewModel, document.getElementById('someElementId'));
+
+ myViewModel.personName();
+ myViewModel.personName('Mary');
+ myViewModel.personName('Mary').personAge(50);
+
+ myViewModel.personName.subscribe(function (newValue) {
+ alert("The person's new name is " + newValue);
+ });
+
+ var subscription = myViewModel.personName.subscribe(function (newValue) { });
+ subscription.dispose();
+}
+
+function test_computed() {
+ function AppViewModel() {
+ var self = this;
+
+ self.firstName = ko.observable('Bob');
+ self.lastName = ko.observable('Smith');
+ self.fullName = ko.computed(function () {
+ return self.firstName() + " " + self.lastName();
+ });
+ }
+
+ function MyViewModel() {
+ this.firstName = ko.observable('Planet');
+ this.lastName = ko.observable('Earth');
+
+ this.fullName = ko.computed({
+ read: function () {
+ return this.firstName() + " " + this.lastName();
+ },
+ write: function (value) {
+ var lastSpacePos = value.lastIndexOf(" ");
+ if (lastSpacePos > 0) {
+ this.firstName(value.substring(0, lastSpacePos));
+ this.lastName(value.substring(lastSpacePos + 1));
+ }
+ },
+ owner: this
+ });
+ }
+
+ function MyViewModel() {
+ this.price = ko.observable(25.99);
+
+ this.formattedPrice = ko.computed({
+ read: function () {
+ return '$' + this.price().toFixed(2);
+ },
+ write: function (value) {
+ value = parseFloat(value.replace(/[^\.\d]/g, ""));
+ this.price(isNaN(value) ? 0 : value);
+ },
+ owner: this
+ });
+ }
+
+ function MyViewModel() {
+ this.acceptedNumericValue = ko.observable(123);
+ this.lastInputWasValid = ko.observable(true);
+
+ this.attemptedValue = ko.computed({
+ read: this.acceptedNumericValue,
+ write: function (value) {
+ if (isNaN(value))
+ this.lastInputWasValid(false);
+ else {
+ this.lastInputWasValid(true);
+ this.acceptedNumericValue(value);
+ }
+ },
+ owner: this
+ });
+ }
+
+ ko.applyBindings(new MyViewModel());
+}
+
+
+function test_observableArrays() {
+ var myObservableArray = ko.observableArray();
+ myObservableArray.push('Some value');
+ var anotherObservableArray = ko.observableArray([
+ { name: "Bungle", type: "Bear" },
+ { name: "George", type: "Hippo" },
+ { name: "Zippy", type: "Unknown" }
+ ]);
+
+ myObservableArray().length;
+ myObservableArray()[0];
+
+ myObservableArray.indexOf('Blah');
+ myObservableArray.push('Some new value');
+ myObservableArray.pop();
+ myObservableArray.unshift('Some new value');
+ myObservableArray.shift();
+ myObservableArray.reverse();
+ myObservableArray.sort(function (left, right) { return left.lastName == right.lastName ? 0 : (left.lastName < right.lastName ? -1 : 1) });
+ myObservableArray.splice(1, 3);
+
+ var someItem: KnockoutObservableArray;
+ myObservableArray.remove(someItem);
+ myObservableArray.remove(function (item) { return item.age < 18 });
+ myObservableArray.removeAll(['Chad', 132, undefined]);
+ myObservableArray.removeAll();
+ myObservableArray.destroy(someItem);
+ myObservableArray.destroy(function (someItem) { return someItem.age < 18 });
+ myObservableArray.destroyAll(['Chad', 132, undefined]);
+ myObservableArray.destroyAll();
+}
+
+function test_bindings() {
+ var currentProfit = ko.observable(150000);
+ ko.applyBindings({
+ people: [
+ { firstName: 'Bert', lastName: 'Bertington' },
+ { firstName: 'Charles', lastName: 'Charlesforth' },
+ { firstName: 'Denise', lastName: 'Dentiste' }
+ ]
+ });
+ var viewModel = { availableCountries: ko.observableArray(['France', 'Germany', 'Spain']) };
+ viewModel.availableCountries.push('China');
+
+ ko.bindingHandlers.yourBindingName = {
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
+ },
+ update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
+ }
+ };
+ ko.bindingHandlers.slideVisible = {
+ update: function (element, valueAccessor, allBindingsAccessor) {
+ var value = valueAccessor(), allBindings = allBindingsAccessor();
+ var valueUnwrapped = ko.utils.unwrapObservable(value);
+ var duration = allBindings.slideDuration || 400;
+ if (valueUnwrapped == true)
+ $(element).slideDown(duration);
+ else
+ $(element).slideUp(duration);
+ },
+ init: function (element, valueAccessor) {
+ var value = ko.utils.unwrapObservable(valueAccessor());
+ $(element).toggle(value);
+ },
+ update: function (element, valueAccessor, allBindingsAccessor) {
+ }
+ };
+ ko.bindingHandlers.hasFocus = {
+ init: function (element, valueAccessor) {
+ $(element).focus(function () {
+ var value = valueAccessor();
+ value(true);
+ });
+ $(element).blur(function () {
+ var value = valueAccessor();
+ value(false);
+ });
+ },
+ update: function (element, valueAccessor) {
+ var value = valueAccessor();
+ if (ko.utils.unwrapObservable(value))
+ element.focus();
+ else
+ element.blur();
+ }
+ };
+ ko.bindingHandlers.allowBindings = {
+ init: function (elem, valueAccessor) {
+ var shouldAllowBindings = ko.utils.unwrapObservable(valueAccessor());
+ return { controlsDescendantBindings: !shouldAllowBindings };
+ }
+ };
+ ko.bindingHandlers.withProperties = {
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
+ var newProperties = valueAccessor(),
+ innerBindingContext = bindingContext.extend(newProperties);
+ ko.applyBindingsToDescendants(innerBindingContext, element);
+ return { controlsDescendantBindings: true };
+ }
+ };
+ ko.bindingHandlers.withProperties = {
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
+ var newProperties = valueAccessor(),
+ childBindingContext = bindingContext.createChildContext(viewModel);
+ ko.utils.extend(childBindingContext, newProperties);
+ ko.applyBindingsToDescendants(childBindingContext, element);
+ return { controlsDescendantBindings: true };
+ }
+ };
+ ko.bindingHandlers.randomOrder = {
+ init: function (elem, valueAccessor) {
+ var child = ko.virtualElements.firstChild(elem),
+ childElems = [];
+ while (child) {
+ childElems.push(child);
+ child = ko.virtualElements.nextSibling(child);
+ }
+ ko.virtualElements.emptyNode(elem);
+ while (childElems.length) {
+ var randomIndex = Math.floor(Math.random() * childElems.length),
+ chosenChild = childElems.splice(randomIndex, 1);
+ ko.virtualElements.prepend(elem, chosenChild[0]);
+ }
+ }
+ };
+
+ var node, containerElem, nodeToInsert, insertAfter, nodeToPrepend, arrayOfNodes;
+ ko.virtualElements.allowedBindings.mySuperBinding = true;
+ ko.virtualElements.emptyNode(containerElem);
+ ko.virtualElements.firstChild(containerElem);
+ ko.virtualElements.insertAfter(containerElem, nodeToInsert, insertAfter);
+ ko.virtualElements.nextSibling(node);
+ ko.virtualElements.prepend(containerElem, nodeToPrepend);
+ ko.virtualElements.setDomNodeChildren(containerElem, arrayOfNodes);
+}
+
+function test_more() {
+ var viewModel = {
+ firstName: ko.observable("Bert"),
+ lastName: ko.observable("Smith"),
+ pets: ko.observableArray(["Cat", "Dog", "Fish"]),
+ type: "Customer",
+ hasALotOfPets: any
+ };
+ viewModel.hasALotOfPets = ko.computed(function () {
+ return this.pets().length > 2
+ }, viewModel);
+ var plainJs = ko.toJS(viewModel);
+
+ ko.extenders.logChange = function (target, option) {
+ target.subscribe(function (newValue) {
+ console.log(option + ": " + newValue);
+ });
+ return target;
+ };
+
+ ko.extenders.numeric = function (target, precision) {
+ var result = ko.computed({
+ read: target,
+ write: function (newValue) {
+ var current = target(),
+ roundingMultiplier = Math.pow(10, precision),
+ newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
+ valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
+
+ if (valueToWrite !== current) {
+ target(valueToWrite);
+ } else {
+ if (newValue !== current) {
+ target.notifySubscribers(valueToWrite);
+ }
+ }
+ }
+ });
+
+ result(target());
+
+ return result;
+ };
+
+ function AppViewModel(one, two) {
+ this.myNumberOne = ko.observable(one).extend({ numeric: 0 });
+ this.myNumberTwo = ko.observable(two).extend({ numeric: 2 });
+ }
+
+ ko.applyBindings(new AppViewModel(221.2234, 123.4525));
+
+ ko.extenders.required = function (target, overrideMessage) {
+
+ target.hasError = ko.observable();
+ target.validationMessage = ko.observable();
+
+ function validate(newValue) {
+ target.hasError(newValue ? false : true);
+ target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
+ }
+
+ validate(target());
+
+ target.subscribe(validate);
+
+ return target;
+ };
+
+ function AppViewModel(first, last) {
+ this.firstName = ko.observable(first).extend({ required: "Please enter a first name" });
+ this.lastName = ko.observable(last).extend({ required: "" });
+ }
+
+ ko.applyBindings(new AppViewModel("Bob", "Smith"));
+
+ var first;
+ this.firstName = ko.observable(first).extend({ required: "Please enter a first name", logChange: "first name" });
+
+ var upperCaseName = ko.computed(function () {
+ return name().toUpperCase();
+ }).extend({ throttle: 500 });
+
+ function AppViewModel() {
+ this.instantaneousValue = ko.observable();
+ this.throttledValue = ko.computed(this.instantaneousValue)
+ .extend({ throttle: 400 });
+
+ this.loggedValues = ko.observableArray([]);
+ this.throttledValue.subscribe(function (val) {
+ if (val !== '')
+ this.loggedValues.push(val);
+ }, this);
+ }
+
+ function GridViewModel() {
+ this.pageSize = ko.observable(20);
+ this.pageIndex = ko.observable(1);
+ this.currentPageData = ko.observableArray();
+
+ ko.computed(function () {
+ var params = { page: this.pageIndex(), size: this.pageSize() };
+ $.getJSON('/Some/Json/Service', params, this.currentPageData);
+ }, this);
+ }
+ this.setPageSize = function (newPageSize) {
+ this.pageSize(newPageSize);
+ this.pageIndex(1);
+ }
+
+ ko.computed(function () {
+ var params = { page: this.pageIndex(), size: this.pageSize() };
+ $.getJSON('/Some/Json/Service', params, this.currentPageData);
+ }, this).extend({ throttle: 1 });
+
+ $(".remove").click(function () {
+ viewModel.items.remove(ko.dataFor(this));
+ });
+ $(".remove").live("click", function () {
+ viewModel.items.remove(ko.dataFor(this));
+ });
+
+ $("#people").delegate(".remove", "click", function () {
+
+ var context = ko.contextFor(this),
+ parentArray = context.$parent.people || context.$parent.children;
+
+ parentArray.remove(context.$data);
+
+ return false;
+ });
+ $("#people").delegate(".add", "click", function () {
+ var context = ko.contextFor(this),
+ childName = context.$data.name() + " child",
+ parentArray = context.$data.people || context.$data.children;
+
+ context.$root.addChild(childName, parentArray);
+
+ return false;
+ });
+ ko.observableArray.fn.filterByProperty = function (propName, matchValue) {
+ return ko.computed(function () {
+ var allItems = this(), matchingItems = [];
+ for (var i = 0; i < allItems.length; i++) {
+ var current = allItems[i];
+ if (ko.utils.unwrapObservable(current[propName]) === matchValue)
+ matchingItems.push(current);
+ }
+ return matchingItems;
+ }, this);
+ }
+ function Task(title, done) {
+ this.title = ko.observable(title);
+ this.done = ko.observable(done);
+ }
+
+ function AppViewModel() {
+ this.tasks = ko.observableArray([
+ new Task('Find new desktop background', true),
+ new Task('Put shiny stickers on laptop', false),
+ new Task('Request more reggae music in the office', true)
+ ]);
+
+ this.doneTasks = this.tasks.filterByProperty("done", true);
+ }
+
+ ko.applyBindings(new AppViewModel());
+ this.doneTasks = ko.computed(function () {
+ var all = this.tasks(), done = [];
+ for (var i = 0; i < all.length; i++)
+ if (all[i].done())
+ done.push(all[i]);
+ return done;
+ }, this);
+}
+
+function test_mappingplugin() {
+ var viewModel = {
+ serverTime: ko.observable(),
+ numUsers: ko.observable()
+ }
+ var data = {
+ serverTime: '2010-01-07',
+ numUsers: 3
+ };
+ viewModel.serverTime(data.serverTime);
+ viewModel.numUsers(data.numUsers);
+
+ var viewModel = ko.mapping.fromJS(data);
+ ko.mapping.fromJS(data, viewModel);
+ var unmapped = ko.mapping.toJS(viewModel);
+
+ var viewModel = ko.mapping.fromJS(data);
+ ko.mapping.fromJS(data, viewModel);
+
+ var myChildModel = function (data) {
+ ko.mapping.fromJS(data, {}, this);
+
+ this.nameLength = ko.computed(function () {
+ return this.name().length;
+ }, this);
+ }
+
+ var oldOptions = ko.mapping.defaultOptions().include;
+ ko.mapping.defaultOptions().include = ["alwaysIncludeThis"];
+
+ var oldOptions = ko.mapping.defaultOptions().copy;
+ ko.mapping.defaultOptions().copy = ["alwaysCopyThis"];
+
+ var someObject;
+ ko.mapping.fromJS(data, {}, someObject);
+ ko.mapping.fromJS(data, {}, this);
+
+ var alice, aliceMappingOptions, bob, bobMappingOptions;
+ var viewModel = ko.mapping.fromJS(alice, aliceMappingOptions);
+ ko.mapping.fromJS(bob, bobMappingOptions, viewModel);
+
+ var obj;
+ var result = ko.mapping.fromJS(obj, {
+ key: function (item) {
+ return ko.utils.unwrapObservable(item.id);
+ }
+ });
+
+ result.mappedRemove({ id: 2 });
+ var newItem = result.mappedCreate({ id: 3 });
+}
+
+function test_misc() {
+ var postbox = new ko.subscribable();
+ postbox.subscribe(callback, target, topic);
+
+ postbox.subscribe(function (newValue) {
+ this.latestTopic(newValue);
+ }, vm, "mytopic");
+ postbox.notifySubscribers(value, "mytopic");
+
+ ko.subscribable.fn.publishOn = function (topic) {
+ this.subscribe(function (newValue) {
+ postbox.notifySubscribers(newValue, topic);
+ });
+
+ return this;
+ };
+
+ this.myObservable = ko.observable("myValue").publishOn("myTopic");
+
+ ko.subscribable.fn.subscribeTo = function (topic) {
+ postbox.subscribe(this, null, topic);
+
+ return this;
+ };
+
+ this.observableFromAnotherVM = ko.observable().subscribeTo("myTopic");
+
+ postbox.subscribe(function (newValue) {
+ this(newValue);
+ }, this, topic);
+
+ ko.bindingHandlers.isolatedOptions = {
+ init: function (element, valueAccessor) {
+ var args = arguments;
+ ko.computed({
+ read: function () {
+ ko.utils.unwrapObservable(valueAccessor());
+ ko.bindingHandlers.options.update.apply(this, args);
+ },
+ owner: this,
+ disposeWhenNodeIsRemoved: element
+ });
+ }
+ };
+
+ ko.subscribable.fn.publishOn = function (topic) {
+ this.subscribe(function (newValue) {
+ postbox.notifySubscribers(newValue, topic);
+ });
+
+ return this;
+ };
+
+ this.myObservable = ko.observable("myValue").publishOn("myTopic");
+
+ var x = ko.observableArray([1, 2, 3]);
+
+ var element;
+ ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
+ $(element).datepicker("destroy");
+ });
+}
\ No newline at end of file