TFS 2012 Web Access Customizations, Part 2: Extension template

In this part of our on-going series about TFS 2012 Web Access customizations we are going look at the actual blueprint for the Work Item control. In the next article you will learn about packaging the extension, providing all the necessary metadata and deploying it to TFS server.  

After reading this article, you should understand how to compose a new Web Access control and what is the minimal code necessary for it.

 

Below is the source code divided into sections with comments below each of the sections and then we include the full source code at the end of the article again for convenience.

 

 TFS.module("TFS.WA.BugList",
 
 [
 
 "TFS.WorkItemTracking.Controls",
 
 "TFS.WorkItemTracking",
 
 "TFS.Core"
 
 ],
 
 function () {
 

TFS is a global variable belonging to Web Access framework which provides a utility method to define your module.
The first parameter of the module is a string which specifies a namespace for the module. Please note that this namespace should match the filename you specified for your .js file (the part before flavor).
The second parameter is an array of strings which specifies the dependencies of your module. The list in the above line is a typical list for the custom control development. Web Access module loader makes sure that the dependent modules are first loaded before your module gets executed.
The last parameter is a function which gets executed when the module is loaded and the actual module implementation lives in here. Optionally you can expose anything you want from your module by return an object.

 

 // module content
 var WITOM = TFS.WorkItemTracking,
 WITCONTROLS = TFS.WorkItemTracking.Controls,
 delegate = TFS.Core.delegate,
 moduleBaseUrl = TFS.getModuleBase("TFS.WA.BugList");

For convenience, we define few shortcuts and get the module base URI to use for including CSS files and/or other resources in our module.

 

 // Constructor for URIs
 function BugList(container, options, workItemType) {
 this.baseConstructor.call(this, container, options, workItemType);
 }

Next up is a constructor for our module. The parameters come from XML definition of the work item in TFS. Notice the explicit call to base class constructor.

 

 // BugList inherits from WorkItemControl BugList.inherit(WITCONTROLS.WorkItemControl, {
 _control: null,
 _loaded: false,

We inherit our extension class from WorkItemControl.

 

 // Initialize the control UI without data (in "blank" state).
_init: function () {
 this._base();
 
 //add css style
 $("<link />").attr("href", moduleBaseUrl + "TFS.WA.BugList.styles.css")
 .attr("type", "text/css")
 .attr("rel","stylesheet")
 .appendTo($("head").first());
 
 this._control = $("<div />").appendTo(this._container);
},

Init function represents component initialization, generally consisting of HTML construction. Here we also add CSS link to the DOM. Important thing to remember is that the initialization is shared across multiple items and is not invoked every time a work item is accessed but rather the first time the control is displayed on the UI. The implication of that is that at this point the control is not associated with any work item. Binding mechanism is used for associating controls with specific items (see next slide).

 

 // Update the control data
invalidate: function (flushing) {
 //...
}, 

Invalidate method is called every time the value in the underlying data store has changed (what field is associated with the control is driven by the XML work item type definition). The change occurs when we the value is saved, reverted or refreshed. If flushing is true then the value is being written to the work item field.

 

 // Clear the control data
 clear: function () {},
 });
 // Register this module as a work item custom control called "BugList"
 WITCONTROLS.registerWorkItemControl("TFS.WA.BugList", BugList); 
 return {
 BugList: BugList
 };
 });

Framework calls clear method when the control needs to reset its state to "blank".
At the end we register our extension with the TFS.

 

bind(workItem)
This method is called when the control is being bound to a new work item. 

unbind(workItem)
This method is called when the control is no longer bound to the specified work item

getControlValue()
This method is called to get the value of the control to write to the corresponding Work Item Tracking field.

cleanup()
This method is called to allow the control to release reference to work item, detach from events, set members to null to free memory which is called after unbind.

_container
This property is a jQuery object (DIV) which contains the control and sub elements are placed. 

_getField()
This method gets the work item form field that corresponds to this control. _getField().getValue() and _getField().setValue(value) are used to read and modify the underlying work item fields. This method returns null if no field is associated with the control in the work item type definition.

 

Here is the above code again in one part:

 TFS.module("TFS.WA.BugList",
[
 "TFS.WorkItemTracking.Controls",
 "TFS.WorkItemTracking",
 "TFS.Core"
],
function () {
 // module content
 var WITOM = TFS.WorkItemTracking,
 WITCONTROLS = TFS.WorkItemTracking.Controls,
 delegate = TFS.Core.delegate,
 moduleBaseUrl = TFS.getModuleBase("TFS.WA.BugList");
 // Constructor for URIs
 function BugList(container, options, workItemType) {
 this.baseConstructor.call(this, container, options, workItemType);
 }
 // BugList inherits from WorkItemControl 
 BugList.inherit(WITCONTROLS.WorkItemControl, {
 _control: null,
 _loaded: false,
 // Initialize the control UI without data (in "blank" state).
 _init: function () {
 this._base();
 
 //add css style
 $("<link />").attr("href", moduleBaseUrl + "TFS.WA.BugList.styles.css")
 .attr("type", "text/css")
 .attr("rel","stylesheet")
 .appendTo($("head").first());
 
 this._control = $("<div />").appendTo(this._container);
 },
 // Update the control data
 invalidate: function (flushing) {
 //...
 },
 // Clear the control data
 clear: function () {},
 //...
 });
 
 // Register this module as a work item custom control called "BugList"
 WITCONTROLS.registerWorkItemControl("TFS.WA.BugList", BugList); 
 return {
 BugList: BugList
};
});
 

In the next article we will take our code and create extension package that can be deployed on the TFS server.