Skip to content

Knockout Enhancements

dotnetwise edited this page Jul 4, 2013 · 6 revisions

You can enhance your knockout development experience by changing a few lines of knockout-version.debug.js file.

Enable observable glyph icon Computed and type hint

  • Replace
ko.observable = function (initialValue) {
    var _latestValue = initialValue;

with

ko.observable = function (initialValue, latestValue) {
	/// <signature>
	/// <summary>Creates a new observable with a custom initial value</summary>
	/// <param name='initialValue' type='Any' optional='true'>Specify any initial value</param>
	/// </signature>

	var _latestValue = initialValue;
	if (typeof latestValue != 'undefined') {
		_latestValue = latestValue;
	}
  • Replace
return observable;

with

    if (window.intellisense) {
    	//enhance intellisense glyphs
    	Object.defineProperty
				? Object.defineProperty(observable, "__observable", { enumerable: false, value: true })
				: (observable.__observable = true);
    	var types = {
    		'undefined': function () {
    			///<signature><summary>Sets the value to the observable</summary><param name='value' type='Any'>Specify the value to set</param>
    			/// <returns type='ko.observable'/></signature>
    			///<signature><summary>Gets the value from the observable</summary><returns type='Object' /></signature>
    		},
    		'string': function () {
    			///<signature><summary>Gets the value from the observable</summary><returns type='String' /></signature>
    			///<signature><summary>Sets the value to the observable</summary><param name='value' type='String'>Specify the value to set</param>
    			/// <returns type='ko.observable'/></signature>
    		},
    		'number': function () {
    			///<signature><summary>Sets the value to the observable</summary><param name='value' type='Number'>Specify the value to set</param>
    			/// <returns type='ko.observable'/></signature>
    			///<signature><summary>Gets the value from the observable</summary><returns type='Number' /></signature>
    		},
    		'boolean': function () {
    			///<signature><summary>Sets the value to the observable</summary><param name='value' type='Boolean'>Specify the value to set</param>
    			/// <returns type='ko.observable'/></signature>
    			///<signature><summary>Gets the value from the observable</summary><returns type='Boolean' /></signature>
    		},
    		'object': function () {
    			///<signature><summary>Sets the value to the observable</summary><param name='value' type='Object'>Specify the value to set</param>
    			/// <returns type='ko.observable'/></signature>
    			///<signature><summary>Gets the value from the observable</summary><returns type='Object' /></signature>
    		},
    		'function': function () {
    			///<signature><summary>Sets the value to the observable</summary><param name='value' type='Function'>Specify the value to set</param>
    			/// <returns type='ko.observable'/></signature>
    			///<signature><summary>Gets the value from the observable</summary><returns type='Function' /></signature>
    		},
    	}
    	var type;
    	if (typeof initialValue == "function") {
    		//if we've got a function redirect definition, by pressing F12/Got to Reference is navigating to that function
    		intellisense.redirectDefinition(observable, initialValue);
    		if (typeof latestValue != "undefined") {
    			//if we've got an extra parameter then, annotate the help of the initialValue function
    			type = initialValue;
    		}
    	}
    	//fallback try to determine the intiialValue's type and pick the proper intellisense function
		if (!type)
			type = types[typeof initialValue] || types.undefined;
		//annotate the returned observable with the proper type function if any
    	type && intellisense.annotate(observable, type);
    }
    return observable;

Well done!

Usage:

  • Strong-typed observable intellisense
var o = ko.observable(123);

Observable strong typed observable intellisense

  • Function redefinition
function Employee(name) {
	/// <summary>Creates a new employee</summary>
	/// <param name="name" type="String">The name of the employee</param>
	/// <field name="name" type="String"> The name of the employee</field>

	this.name = name;
}
function EmployeeHelper(name) {
	///<signature>
	///	<summary>Sets the value to the observable</summary>
	///	<param name='value' type='Employee'>Specify the value to set</param>
	///	<returns type='ko.observable'/>
	///</signature>
	///<signature>
	///	<summary>Gets the value from the observable</summary>
	///	<returns type='Employee' />
	///</signature>

}
var obs = ko.observable(EmployeeHelper, new Employee("John"));
var emp = obs();
  • Getting proper intellisense while getting the observable Observable getting observable

  • Getting proper intellisense after extracting observable's value Observable getting value's intellisense

  • ...and getting proper intellisense while setting it Observable setting a new value

Enable observableArray glyph icon Computed hint

  • Replace
ko.observableArray = function (initialValues) {

with

ko.observableArray = function (initialValues, latestValues) {
    /// <signature>
    /// <summary>Creates a new observable array with a custom initial values</summary>
    /// <param name="initialValues" type="Array" optional="true">Specify an array as its initial values</param>
    /// </signature>
  • Replace
    ko.utils.extend(result, ko.observableArray['fn']);
    return result;
}

with

     if (typeof latestValues == "undefined" && typeof initialValues != "function") {
    	latestValues = initialValues;
    	initialValues = function () {
    		///<signature><summary>Sets the value to the observableArray</summary><param name='value' type='Array'>Specify the value to set</param>
    		/// <returns type='ko.observableArray'/></signature>
    		///<signature><summary>Gets the value from the observableArray</summary><returns type='Array' /></signature>
    	}
    }
    var result = ko.observable(initialValues, latestValues);
    if (window.intellisense) {
    	//enhance intellisense glyphs
    	Object.defineProperty
				? Object.defineProperty(result, "__observableArray", { enumerable: false, value: true })
				: (result.__observableArray = true);
    }
}

Well done!

Usage:

  • Strong-typed observableArray intellisense
var o = ko.observableArray(["abc"]);

ObservableArray strong typed

  • Function redefinition
function Employee(name) {
	/// <summary>Creates a new employee</summary>
	/// <param name="name" type="String">The name of the employee</param>
	/// <field name="name" type="String"> The name of the employee</field>

	this.name = name;
}
function EmployeeHelper(name) {
	///<signature>
	///	<summary>Sets the value to the observable</summary>
	///	<param name='value' type='Employee[]'>Specify the value to set</param>
	///	<returns type='ko.observable'/>
	///</signature>
	///<signature>
	///	<summary>Gets the value from the observable</summary>
	///	<returns type='Employee[]' />
	///</signature>

}
var obs = ko.observableArray(EmployeeHelper, [new Employee("John")]);
obs()
  • Getting proper intellisense while getting the observable ObservableArray function definition example

  • Getting proper intellisense after extracting observable's value ObservableArray getting value's intellisense

  • Getting proper intellisense when addressing Array methods ObservableArray getting array intellisense

  • ...and getting proper intellisense while setting it ObservableArray setting a new value

Enable computedObservable glyph icon Computed hint

Also enables redirect to the read function when pressing F12/Go to reference

Replace

    ko.subscribable.call(dependentObservable);
    ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);

with

    if (window.intellisense) {
    	//enhance intellisense glyphs
    	Object.defineProperty
				? Object.defineProperty(dependentObservable, "__observableComputed", { enumerable: false, value: true })
				: (dependentObservable.__observableComputed = true);
    	intellisense.redirectDefinition(result, readFunction);
    	intellisense.annotate(result, readFunction);
    }

    ko.subscribable.call(dependentObservable);
    ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);

Great job!