Adding Content Files to Work Item Custom Control Extension Package

In the previous 2 posts, we talked about how you can develop and deploy work item custom controls using the new architecture of TF Web Access 2012. In the previous posts we developed work item custom controls using HTML and JavaScript. However, in a real world scenario, developers will often need to use content files like images or css for a custom control. This post is about how to include these files in a WICC extension package.

We will continue to use VoteButton as the sample custom control and add an icon to the button.

First thing you need to do is have a reference to the base URL of the module. This URL is used to construct a reference to the content files included in the extension package. Defining the base URL module scoped is better because it will be available to all the controls inside that module:

TFS.module("ACME.VoteButton", ["TFS.WorkItemTracking.Controls", "TFS.WorkItemTracking", "TFS.Core"], function () {
var WITOM = TFS.WorkItemTracking,
WITCONTROLS = TFS.WorkItemTracking.Controls,
delegate = TFS.Core.delegate,
moduleBaseUrl = TFS.getModuleBase("ACME.VoteButton");

// Constructor for VoteButton
function VoteButton(container, options, workItemType) {, container, options, workItemType);

Using this base URL, it is really easy to construct the URL to access any content file using the name specified in the extension package.

_init: function () {

// Create vote button
this._control = $("<button type='submit' />").appendTo(this._container).bind("click", delegate(this, this._onClick));

// Add vote icon
$("<img />").attr("src", moduleBaseUrl + "vote.png").attr("align", "absMiddle").prependTo(this._control);

// Add button text
this._buttonText = $("<span />").text("Vote").appendTo(this._control);

The following changes also need to be made in order to have the control work correctly.

// Update the control data
// Framework calls this method when the control needs to update itself, such as when:
// - work item form is bound to a specific work item
// - underlying field value has changed due to rules or another control logic
invalidate: function (flushing) {

// Get the vote count from the underlying field
var voteCount = this._getField().getValue() || 0;

// Display the number of votes if any
if (voteCount > 1) {
this._buttonText.text(voteCount + " votes");
} else if (voteCount == 1) {
this._buttonText.text(voteCount + " vote");
} else {

// Clear the control data
// Framework calls this method when the control needs to reset its state to "blank", such as when:
// - work item form is unbound from a specific work item
clear: function () {

Then the extension package is recreated by including the content file as well.


After uploading the package to TFS, VoteButton should be seen with an icon.


Beside images, you can have your own css file inside the package. With the following JavaScript trick, it is possible to get css file working for the document.

$("<link />").attr("href", moduleBaseUrl + "my.css")
.attr("type", "text/css")
.attr("rel", "stylesheet")

Let us know if you have any questions or feedback.

Comments (11)
  1. Andrew says:

    Great work so far! Do you have any plans to post a blog about creating new tabs in Web Access?

  2. Serkan Inci says:


    Adding a hub through extensions is not supported at the moment unfortunately. However, we are considering to support it as we get requests about it. We'll let you know in this blog about the availability.


  3. InnocentBoy says:

    Hi Serkan,

    Can you pls mention how add radio button/ checkbox to a work item.


  4. Serkan Inci says:


    For checkbox, you don't need a custom control. If you set the type of your field to "Boolean", you can use FieldControl to have your field displayed as a checkbox, like following:

    <Control FieldName="My.Boolean.Field" Type="FieldControl" Label="Checkbox Label" />

    For radio buttons, you can take this sample code as the base and in the initialize, instead of creating button, creating the radio button will do the trick for you.

    Let me know if you more questions.

  5. Jeffry van de Vuurst says:

    Hi Serkan,

    Excellent info on Web Access customization. Is there any official documentation about the Web Access client side object model? What exactly can we customize, what namespaces are there, etc? I would really like to learn more about customizing this because the new Web Access is very promising!



  6. kfir b says:


    i want to put an custom control of textbox type

    how do i add it and how can i get the text value from the control

  7. Oleg Markitanov says:

    Hi, Serkan!

    Great work!

    Will create a button with which you can load the file into TFS through a web interface (TFS Web Access)?


  8. Tom says:


    Thanks for the information, seeing as there is like no documentation this is quite helpful.

    Can I ask how you would go about adding a custom .js file?

  9. Serkan Inci says:

    @Tom, would you like to add a 3rd party library along with your custom control implementation?

  10. Serkan Inci says:

    @Oleg Markitanov,

    I'm not sure I understood your question correctly. Do you want to have a custom control with an upload button included? You should be able to do it easily by adding input type of file to the provided container using jQuery.

    However, I'd like to know more about it to see how it's different that ordinary AttachmentsControl.

  11. Bayram says:

    For those who are interested (and ar eworking with a text field that contains "Yes" or "No", I have created this custom  "AzCheckBox"







       function () {

           // module content

           var WITOM = TFS.WorkItemTracking,

               WITCONTROLS = TFS.WorkItemTracking.Controls,

               delegate = TFS.Core.delegate;

           // Constructor for AzCheckBox

           function AzCheckBox(container, options, workItemType) {

     , container, options, workItemType);


           AzCheckBox.inherit(WITCONTROLS.WorkItemControl, {


           _init: function () {


               this._control = $("<input type='checkbox' >").appendTo(this._container).bind("change", delegate(this, this.onChanged));


           invalidate: function (flushing) {

               if (this._readOnly) {

                   this._control.attr("disabled", "disabled");

               } else {



               this._control.attr("checked", this._getField().getValue());


           getValue: function () {

               return this._control.attr("checked") ? true : false;


           clear: function () {

               this._control.attr("checked", false);


           onChanged : function (e) {




       WITCONTROLS.registerWorkItemControl("AzCheckBox", AzCheckBox);

           return {AzCheckBox: AzCheckBox};


    <WebAccess version="12.0">

     <plugin name="AzCheckBox" vendor="" moreinfo="" version="1.0.0" >

     <modules >

       <module namespace="AzCheckBox" loadAfter="TFS.WorkItemTracking.Controls"/>  




Comments are closed.

Skip to main content