AX7 allows you to develop new user interface components called ‘extensible controls’ using HTML, Javascript and other web programming technologies. You can also integrate any of the thousands of existing web based plugins and code libraries inside AX user interface and use them directly with AX data. Building ‘extensible controls’ in AX offers endless possibilities to enrich standard AX7 user interface and forms.

However, learning how to write an extensible control is a subject of its own. It is not straightforward and simple as programming other parts of AX and I think having a good knowledge in HTML and web programming is a must to be able to understand it. The documentation and github examples provided by Microsoft is limited, but by studying the functionality yourself, doing examples and examining existing controls in AX7 webroot folder, pieces of the puzzle start to fit together.

Here in this article I will show the basics of how to integrate a third party web plugin and use it in an AX7 form. I have chosen weareoutman’s ClockPicker as an example and will show how to create an alternative, better looking AX time edit control with this plugin and add it to AX forms:

Capture3

 

Please download the latest SDK for the plugin from the link below, and study the readme file before you start using the SDK (MIT license) :

https://weareoutman.github.io/clockpicker/

Control’s HTML document

First we need to create a simple HTML document which contains our control and links to it’s script libraries like below. AX7 web application already uses JQuery, so you do not need to link it in your web page, but it does not use ‘bootstrap’, and I do not recommend adding bootstrap to AX7 web pages. In fact, be really careful that the libraries or style sheets you add here in your control document dont conflict with AX7 standard code and styles. AX7 uses its own UI library, so we skip the bootstrap option for the plugin and use it without. Our basic HTML document looks like this :

	<link rel="stylesheet" type="text/css" href="/Resources/styles/jquery-clockpicker.min.css">
<div id="ClockPickerControl" data-dyn-bind="visible: $data.Visible,sizing: $dyn.layout.sizing($data)" class="Auto input_container">
<label data-dyn-role="Label" data-dyn-bind="Text: $data.Label" class="label staticText"></label>
<input type="text" class="textbox field allowTextSelection" /></div>
<script src="/Resources/scripts/jquery-clockpicker.min.js"></script>
<script src="/Resources/scripts/ClockPickerControl.js"></script>

The $data variable holds the properties of our control’s current data instance (we will come to that later) and we can dynamically bind the control properties of AX7 to various properties of the HTML element using “data-dyn-bind” property AX7 provides for us. After it is bound dynamically, anytime you change the value in AX7 code, it is reflected to the HTML control, so AX code and HTML side is linked. There are so many useful other “data-dyn-bind” functions that you can create server side (ASP) programming like functionalities, such as conditional if blocks and foreach loops. Please check “Extensible control programming reference” from the links below for a list of those interesting functions.

We could have used “data-dyn-bind=”attr: {value: $data.DefaultTime}”” on our input element to dynamically bind our control’s value to the HTML input element’s value attribute; but in our example, that does not work. The initialization of the clockpicker plugin destroys the binding done on the input element by the data-dyn-bind attribute.

The css classes I assigned are just copied from standard AX7 input boxes, by default AX does not have borders for input boxes and you need to set your classes correctly to be able to see your input control.

The scripts and style sheet links we add into our HTML are later parsed by AX7 application and inserted into the webpage header automatically if we use the control in our form. So we can add as much links here as we want.

The ClockPickerControl.js is our control’s javascript code; for now just create an empty Javascript for that and save it to your desktop.

Save your HTML file to your desktop, with extension “htm” instead of “html” and forward to next step of adding the resources.

Control’s Resources

In AX7, added resources consists of various web elements, like html pages, css sheets, images, javascript files which will be copied into the related directories of AX7 web application under “Resources” main folder:

Capture4

Like we did in our HTML file above, we can then link to those resources using \Resource\<Type> path. For our extensible control we need to insert the following resources which are being used by our HTML page above:

Capture2

Control’s build class

On AX side, we need to create two classes for AX to recognize our control and add our control to AX control library: build class and runtime class. Our build class is the one which is used by the VS AX form designer, containing properties of our control. We add following properties, which “DefaultTime” being the value of our edit box :


[FormDesignControlAttribute(&quot;ClockPickerControl&quot;)]
class ClockPickerControlBuild extends FormBuildControl
{
str defaultTime,doneText,label;

[FormDesignPropertyAttribute(&quot;DefaultTime&quot;, &quot;Data&quot;)]
public str parmDefaultTime(str _defaultTime = defaultTime)
{
if (!prmIsDefault(_defaultTime))
{
defaultTime = _defaultTime;
}
return defaultTime;
}

[FormDesignPropertyAttribute(&quot;DoneText&quot;, &quot;Data&quot;)]
public str parmDoneText(str _doneText = doneText)
{
if (!prmIsDefault(_doneText))
{
doneText = _doneText;
}
return doneText;
}

[FormDesignPropertyAttribute(&quot;Label&quot;, &quot;Appearance&quot;)]
public str parmLabel(str _label = label)
{
if (!prmIsDefault(_label))
{
label = _label;
}
return label;
}

}

The second parameter in our method’s FormDesignPropertyAttribute() is the name of the tab page in properties window, which our property is displayed under; but at the time of writing that does not work, all added attributes appear in “Misc” tab in properties.

Control’s runtime class

This is the main class of our control which gets the design time properties from build class and sends them to HTML side for processing, also handles the runtime bindings on HTML side. Methods and variables with FormCommandAttribute or FormPropertyAttribute on this class can be accessed directly from the Javascript code of your control by using the ‘$control’ and ‘$data’ objects. For example, to be able to call a method in this class, you use ‘$dyn.callFunction()’ in JS. I will not cover all of it in this tutorial.

The HTML file for your control is linked in the header of this class in FormControlAttribute, or using this.setResourceBundleName method. The “template id” you set here for your control is important, this will be the unique name of your control which is used in AX, HTML and Javascript code of your control:


[FormControlAttribute('ClockPickerControl', '/Resources/html/ClockPickerControl', classstr(ClockPickerControlBuild))]
class ClockPickerControl extends FormTemplateControl
{
FormProperty defaultTime;
FormProperty doneText;
FormProperty label;

[FormPropertyAttribute(FormPropertyKind::Value, &quot;DefaultTime&quot;)]
public str parmDefaultTime(str _value = defaultTime.parmValue())
{
if (!prmIsDefault(_value))
{
defaultTime.setValueOrBinding(_value);
}

return defaultTime.parmValue();
}

[FormPropertyAttribute(FormPropertyKind::Value, &quot;DoneText&quot;)]
public str parmDonetext(str _value = doneText.parmValue())
{
if (!prmIsDefault(_value))
{
doneText.setValueOrBinding(_value);
}

return doneText.parmValue();
}

[FormPropertyAttribute(FormPropertyKind::Value, &quot;Label&quot;)]
public str parmLabel(str _value = label.parmValue())
{
if (!prmIsDefault(_value))
{
label.setValueOrBinding(_value);
}

return label.parmValue();
}

public void new(FormBuildControl _build, FormRun _formRun)
{
super(_build, _formRun);

this.setTemplateId('ClockPickerControl');
this.setResourceBundleName('/Resources/html/ClockPickerControl');

defaultTime = properties.addProperty(methodStr(ClockPickerControl, parmDefaultTime), Types::String);
donetext = properties.addProperty(methodStr(ClockPickerControl, parmDoneText), Types::String);
label = properties.addProperty(methodStr(ClockPickerControl, parmLabel), Types::String);
}

public void applyBuild()
{
super();

ClockPickerControlBuild build = this.build();

if (build)
{
this.parmDefaultTime(build.parmDefaultTime());
this.parmDoneText(build.parmDoneText());
this.parmLabel(build.parmLabel());
}
}

}

Control’s Javascript code

To be able to initialize our control on JS side, we need to declare our control’s javascript object in a separate javascript file which we have linked in our HTML page before as “ClockPickerControl.js”. Object constructor definition for our control is assigned to $dyn.controls.ClockPickerControl variable with the same template id as the one we used in our runtime AX class (be careful to use same template id for your control in all those definitions, or your control will not work ok). And Javascript object prototype for our control is declared as inheriting from “$dyn.ui.Control” object. Here in the prototype declaration, you can add new properties and functions for your control which will be shared by all instances of your control (check “Javascript objects” for more information on object and prototype declarations)

The code below is mostly the basic template for all extensible control javascript files, except we need to call the plugin initialization for our clockpicker inpit element. Also because I could not dynamically bind the ”DefaultTime” value of my control to the HTML input element, I bind it manually using $dyn.observe method for my property and ‘change’ event of the input element:


(function () {
'use strict';

$dyn.controls.ClockPickerControl = function (data, element) {
$dyn.ui.Control.apply(this, arguments);

var self = this;

self.$clockPickerElement = $(element).find(&quot;input&quot;);

self.$clockPickerElement.clockpicker({
donetext: data.DoneText,
twelvehour: true,
autoclose:true
});

self.$clockPickerElement.change(function () {
data.DefaultTime(self.$clockPickerElement.val());
});

$dyn.observe(data.DefaultTime, function (defaultTime) { self.$clockPickerElement.val(defaultTime) })

};

$dyn.controls.ClockPickerControl.prototype = $dyn.ui.extendPrototype($dyn.ui.Control.prototype, {
init: function (data, element) {
$dyn.ui.Control.prototype.init.apply(this, arguments);
}
});
})();

Using the $dyn.observe() method, you can add event handlers to changes in AX7 Web API ‘observable’ variables. By default all control properties are observable variables and you can create more observable variables in AX7 JS API if you need. You can then attach event handlers to track changes to those variables. Please check the reference document for examples and more information on that.

Putting it together

After you build your solution, you can see your new control on the ax controls list and add it to your form :

Capture5.PNG

And you can set the properties of the control from the standard ax properties window and run your form.

Also the properties you have added are acessible from the program code, just like other form controls in AX :


[Control(&quot;Button&quot;)]
 class DisplayTime
 {
 /// &amp;lt;summary&amp;gt;
 ///
 /// &amp;lt;/summary&amp;gt;
 public void clicked()
 {
 super();

info(ClockPickerControl1.parmDefaultTime());
 }

}

[Control(&quot;Button&quot;)]
 class SetTime
 {
 /// &amp;lt;summary&amp;gt;
 ///
 /// &amp;lt;/summary&amp;gt;
 public void clicked()
 {
 super();

ClockPickerControl1.parmDefaultTime(&quot;5:30AM&quot;);
 }

}

Capture6

That’s all the basics for now, if you want to extend the control further, you can make the time property as a time datatype, add view/edit mode support, new control properties for 12 hour mode and others, bind it to a data source and make it multi language, just there are so many possibilities..

You can download the source code of this blog post from the following link :

https://github.com/sertanyaman/SertanDevAXExamples/blob/master/ClockPickerControlDemo.zip

Other useful links to study on AX7 extensible controls :

extensible-control-programming-reference

Dynamics-AX-Extensible-Control-Samples Github

build-extensible-control

extensible-controls-layout

 

 

 

 

 

One thought on “Using 3rd party Web components in AX7; an introduction to extensible controls

  1. Thanks for sharing. Would be nice if you could include steps on how to setup and check whether the pre-requisites are setup correctly.

Leave a Reply