UI Widgets

An HTML JS widget is a visual component created when a browser renders an HTML element (container), JavaScript code and CSS stylesheets on a page. PhoneJS comes with a big library of UI widgets. When using these widgets in PhoneJS applications, the framework automatically changes widgets' look and feel to match the platform they are viewed on. Hence, your application looks and behaves like a fully native application.

Add a Widget

There are two possible approaches to creating a PhoneJS widget. Review both of these approaches to pick the one that suits your project best.

jQuery Approach

Add a div element within the body of the required view.

HTML
<div id="buttonContainer"></div>

PhoneJS supplies jQuery plugins for each widget. The following code demonstrates how to create a button within the "buttonContainer" container using the dxButton jQuery plugin.

JavaScript
$(function () {
    $("#buttonContainer").dxButton();
});

To configure a widget, pass a configuration object as the constructor's parameter. The properties of this object represent the widget's configuration options. To specify them, set the required values to the configuration object's properties.

JavaScript
$(function () {
    var showHelloWorld = function () {
        alert("Hello world!");
    };

    $("#buttonContainer").dxButton({
        clickAction: showHelloWorld,
        text: "Click me!"
    });
});

To create a widget within a view of your PhoneJS application, handle the viewRendered event of the HtmlApplication object. To specify a separate handler for a particular view only, add the viewShown field to the view's ViewModel and assign the handling function to it.

HTML
JavaScript
<div data-options="dxView:{name:'home', title:'Home'}">
    <div data-options="dxContent: { targetPlaceholder: 'content'}">
        <div data-bind="dxButton: { text: 'Click me!', clickAction: showHelloWorld }"></div>
    </div>
</div>
MyApp.home = function(params) {
    return {
        viewShown: function () {
            $("#buttonContainer").dxButton({
                clickAction: showHelloWorld,
                text: "Click me!"
            });
        }      
    };
};

Knockout Approach

PhoneJS supplies custom Knockout bindings for each widget.

HTML
<body>
  <div id="buttonContainer" data-bind="dxButton: {}"></div>
</body>

To configure a widget, specify a configuration object. The properties of this object represent the widget's configuration options. To specify them, set the required values for the configuration object's properties.

HTML
<body>
  <div id="buttonContainer" data-bind="dxButton: { clickAction: showHelloWorld, text: 'Click me!' }"></div>
</body>

In the code above, the dxButton's clickAction option is set to a value that is specified by the accompanying JavaScript code below.

JavaScript
var myViewModel = {
    showHelloWorld: function() {
        alert("Hello world!");
    }
};
ko.applyBindings(myViewModel);

To activate Knockout, call ko.applyBindings() as it was done in the code above.

PhoneJS applications are designed based on the MVVM pattern. To automatically update UI parts of your application whenever a data model changes, make use of the "Dependency Tracking" feature offered by Knockout. To create a widget within a view of your PhoneJS application, add the widget element to the required layout placeholder of the view markup.

HTML
<div data-options="dxView:{name:'myView', title:'Home'}">
    <div data-options="dxContent: { targetPlaceholder: 'content'}">
        <div data-bind="dxButton: { text: 'Click me!', clickAction: showHelloWorld }"></div>
    </div>
</div>

The widget's options can be bound to the fields of the view's ViewModel, as the clickAction option specified above is bound to the showHelloWorld function defined within the ViewModel below.

JavaScript
MyApp.myView = function(params) {
    return {
        showHelloWorld: function() {
            alert("Hello world!");
        }
    }
});

NOTE: You don't have to call the ko.applyBindings() function to perform binding, because this function is called internally when displaying a view.

Customize Widget Item Appearance

The PhoneJS framework includes widgets intended to display multiple elements of the same type. The most obvious example of such a widget is the dxList widget. It consists of items that can have a simple textual presentation or a more complex one - with images and so on. More examples of such widgets are: the dxGallery widget - a list of images, the dxTileView widget - a list of tiles, dxToolbar - a list of toolbar items, etc. When configuring such widgets, an HTML template for items must be specified. In this topic, you will learn how to provide an item template for a widget.

Use one of the following techniques.

Use a Default Item Template

For each item collection widget a default item template is defined out-of-the-box. Default templates are based on a predefined set of fields in the widget data source, requiring you to provide the required set of fields for your widget's data source, so that widget items are displayed using a default template. The following are the fields that are used in a default item template of any widget.

  • disabled
    Specifies whether the list item is disabled.
  • visible
    Specifies whether the list item is visible.
  • html
    Specifies the html code inserted into the item element.
  • text
    Specifies the text inserted into the item element.

However, additional fields can be required for item templates of certain widgets. For instance, a default template for the dxList widget is based on the set of fields above. However, the key field is also required to specify the group to which an item is related. To learn what set of fields is required for a certain widget, refer to the dataSource option description of this widget.

In some scenarios, it is enough to specify a simple array as a widget data source. In this instance, a default item template represents the text binding to the current array value.

Customize a Default Template

You can customize an item element after it has been rendered. For this purpose, assign a function to the itemRenderedAction option. In this function, use the itemData field of the object passed as a parameter to access an object representing the widget item being rendered. To access the HTML element representing the rendered item, use the itemElement field of the parameter object.

Implement a Custom Item Template for a Widget

If a default item template is not appropriate for your task and customization of a default render result is not enough, implement a custom item template based on custom data source fields. Use the jQuery or Knockout approach to specify the structure of the HTML element representing a widget item.

The examples below imply that the array passed to the dataSource option of the widget has the following structure.

JavaScript
tileViewData = [
    {
        name: 'Alabama',
        area: 135765,
        population: 4822023,
        capital: 'Montgomery'
    },
    {
        name: 'Alaska',
        area: 1717854,
        population: 731449,
        capital: 'Juneau'
    },
    ...
];
  • jQuery Approach

    To specify the structure of a rendered item element using jQuery, widgets with item collections contain the itemRender configuration option. The function assigned to this option is called each time a widget item is rendered. It should have the following input parameters.

    • itemData - an object representing the rendered item. (If you assigned an array of objects to the widget's dataSource configuration option, this parameter will contain the array element representing the rendered item.)
    • itemIndex - an index of the rendered item.
    • itemElement - a container element containing the rendered item.

    The following example illustrates a function for rendering items of a dxTileView widget.

    JavaScript
    itemRenderer = new function(itemData, itemIndex, itemElement){
        var result = "<h1>" + itemData.name + "</h1>";
        result += "<p>Area: <i>" + itemData.area + "</i> km2</p>";
        result += "<p>Population: <i>" + itemData.population + "</i></p>";
        result += "<p>Capital: <i>" + itemData.capital + "</i></p>";
        return result;
    };

    Assign the function to the widget's itemRender configuration option.

    JavaScript
    $(function(){
        $("#tileViewContainer").dxTileView({ 
            dataSource: tileViewData, 
            itemRender: itemRenderer
        });
    });

    In addition to the itemRender option, some widgets expose additional configuration options that are similar to the itemRender option but return a template for another part of the widget. For instance, if you use the dxList widget to display a grouped list, you can specify the structure of elements representing group header items in the same way as described above. In this case, the function rendering group header items should be assigned to the groupRender option of the widget. For more information, see the dxList widget description.

  • Knockout

    To specify the widget item structure using the Knockout approach, create an HTML container element within the widget and apply the data-options attribute set to dxTemplate.

    HTML
    <div data-bind="dxTileView:{dataSource: tileViewData}">
        <div data-options="dxTemplate:{name:'item'}">            
        </div>
    </div>

    Insert the required structure in the newly added dxTemplate element.

    HTML
    <div data-bind="dxTileView:{dataSource: tileViewData}">
        <div data-options="dxTemplate:{name:'item'}">
            <h1 data-bind="text:name"></h1>
            <p>Area: <i data-bind="text:area"></i> km2</p>
            <p>Population: <i data-bind="text:population"></i></p>
            <p>Capital: <i data-bind="text:capital"></i></p>
        </div>
    </div>

    The default name of the template element is "item". If you use a different template name, you should assign it to the itemTemplate configuration option of the widget.

    HTML
    <div data-bind="dxTileView:{dataSource: tileViewData, itemTemplate:'myItem'}">
        <div data-options="dxTemplate:{name:'myItem'}">
            ...
        </div>
    </div>

    In addition to the itemTemplate option, some widgets expose additional configuration options that are similar to the itemTemplate option but specify a template for another part of the widget. For instance, you can specify a template for group header items of the dxList widget that displays a grouped list. Create a template element as shown above. The default name of the group header item template is "group". If you specified a different name, assign it to the widget's groupTemplate configuration option. For more information, see the widget description.

Provide Several Item Templates for a Widget

You may have several templates defined within a widget. To apply the required one in a specific context, assign a function to the widget's itemTemplate option. The return value of this function must be a string representing the name of the required template.

Provide a Common Item Template for Widgets

When you have several widgets with item collections, you may need to define a common custom item template for them. For this purpose, factor out a template into a separate element, as demonstrated below.

HTML
<script id="person-template">
    <h3 data-bind="text: name"></h3>
    <p>Address: <span data-bind="text: address"></span></p>
</script>

To set the common template as an item template for a widget, assign one of the following values to the widget's itemTemplate option.

  • Assign a jQuery object representing the template's container.
  • Assign a DOM Node representing the template's container.
  • Assign a function that returns the jQuery object or a DOM Node representing the template's container.

Provide a Custom Template for an Item

You can provide a custom template for a certain item(s) specifically. For this purpose, introduce a template within the widget element or factor out the template into a separate element. To set the required template for a widget item, specify the template field within the data source object that represents this item.

JavaScript
tileViewData = [
    {
        name: 'Alabama',
        area: 135765,
        population: 4822023,
        capital: 'Montgomery',
        //template to this certain item
        template: 'specific'
    },
    {
        name: 'Alaska',
        area: 1717854,
        population: 731449,
        capital: 'Juneau'
    },
    ...
];
HTML
<div data-bind="dxTileView:{dataSource: tileViewData, itemTemplate:'myItem'}">
    <div data-options="dxTemplate:{name:'myItem'}">
        ...
    </div>
    <div data-options="dxTemplate:{name:'specific'}">
        ...
    </div>
</div>

Handle Events

To enable end-user interaction, most PhoneJS widgets include options to which Actions are assigned. These actions are performed when a certain event occurs. Clicks and other widget events can be handled in such a manner. An action can navigate to an external or internal URL, to a specified view with or without parameters, or perform a specified function. Below are examples of how actions of different types are assigned to the Button widget's clickAction option.

HTML
<div data-bind="dxButton: { clickAction: 'http://google.com' }"></div>
<div data-bind="dxButton: { clickAction: '#details' }"></div>
<div data-bind="dxButton: { clickAction: '#User/{id}' }"></div>
<div data-bind="dxButton: { clickAction: function() { alert('Clicked!') } }"></div>

Access a Widget

You may need to access a widget during the application flow to specify its properties or call its functions. To access a widget instance, use its jQuery plugin and pass "instance" as a parameter. The following code demonstrates how to do this.

JavaScript
var button = $("#buttonContainer").dxButton("instance");

Use the widget's instance to access its members. In addition, you can get and set the widget's configuration options.

Change Options

Once you specified options in the configuration object, you may need to change them dynamically. In dependence which approach you used to create a widget, use the corresponding technique to change a specified value.

jQuery Approach

Use the following techniques when working with options in code:

Get Option Value

When you have an instance of a widget accessed, you can get or set its configuration options at runtime. To do this, use one of the following approaches.

  • Use option() function of a widget instance

    Call the option function passing the name of the option whose value you want to get.

    JavaScript
    var button = $("#buttonContainer").dxButton("instance");
    var buttonText = button.option('text');
  • Use the widget's plugin

    Call the function that represents the widget's jQuery plugin passing "option" as the first parameter and the name of the required option as the second parameter.

    JavaScript
    var buttonText = $("#buttonContainer").dxButton('option','text');

Set an Option

To set a configuration option to a new value, pick from two approaches analogous to the approaches used for getting the option value presented above.

  • Use the option() function of a widget instance

    Call the option function passing the option name as the first parameter and a new value as the second value.

    JavaScript
    var button = $("#buttonContainer").dxButton("instance");
    button.option('text', 'Click');
  • Use the widget's plugin

    Call the function that represents the widget's jQuery plugin passing "option" as the first parameter, the name of the required option as the second parameter and a new value for the option as the third parameter.

    JavaScript
    $("#buttonContainer").dxButton('option','text','Click');

After an option change, the widget will be refreshed automatically.

NOTE: If you perform a chain of option changes, wrap it by the calls of the widget's beginUpdate and endUpdate functions. In this instance, the changes will be applied all together after the end of transaction.

Set Several Options

You can set more than one option at a time. In such a case, define a configuration object whose properties represent the options that are set to new values. Choose the appropriate approach to pass this object.

  • Use the option() function of a widget instance

    JavaScript
    var button = $("#buttonContainer").dxButton("instance");
    button.option({
        text: 'Click',
        type: 'danger'
    });
  • Use the widget's plugin

    JavaScript
    $("#buttonContainer").dxButton({
        text: 'Click',
        type: 'danger'
    });

    NOTE: This approach recalls the way you create a widget. However, if there is a widget created in a specified container, the next time the widget's plugin is called with the configuration object specified, the options will be merged.

Knockout Approach

When using a Knockout approach to create a widget, some of the widget options or all of them are bound to ViewModel fields.

JavaScript
var viewModel = {
    buttonText = "Click me";
};
HTML
<div data-bind="dxButton: {text: buttonText}"></div>

Therefore, to get an option value, get the value of the corresponding ViewModel field.

JavaScript
var text = viewModel.buttonText;

To change an option value dynamically during application flow and update the widget in response to the option change, utilize observables.

JavaScript
var viewModel = {
    buttonText = ko.observable("Click me");
};

viewModel.changeText = function () {
    viewModel.buttonText('Title has been changed');
};

NOTE: Only options that are specified on the first level of the configuration object can be made observable.

Configure Widget Animation options

The PhoneJS framework allows you to customize the showing and hiding of animation options for widgets that overlay the main screen (dxLoadPanel, dxOverlay, dxPopup and dxToast). Each of these widgets contains an animation option that takes on an animation configuration object.

HTML
<div data-bind="dxOverlay: {visible: overlayVisible, animation: animationConfig}">
  <p>Overlay contents</p>
</div>

The animation configuration object in turn contains the show and hide fields that take on animation configuration objects for showing and hiding the widget appropriately. Objects passed to these fields have the same structure and include the fields described below.

  • complete
    A function called after the animation has been finished.

  • delay
    A number specifying the time period to wait before the animation execution.

  • duration
    A number specifying the time in milliseconds spent on animation.

  • easing
    A string specifying the type of an easing function used for animation. PhoneJS supports predefined jQuery easing ("linear" and "swing") and CSS transition timing functions ("linear", "ease", "ease-in", "ease-out", "ease-in-out", "cubic-besier(0,1,1,0)", etc.). For more information on CSS transition timing functions, see http://www.w3schools.com/cssref/css3prtransition-timing-function.asp. You can also register a custom easing function using jQuery and pass its name to the easing option.

    JavaScript
    $.easing.myEasing = function(t, millisecondsSince, startValue, endValue, totalDuration) {
        if(t<0.5) {
            return t*4;
        } else {
            return -2*t + 3;  
        }
    };
    animationOptions = {
        show: {
            duration: 2000,
            type: "slide",
            from: { left: -300 },
            easing: "myEasing"
        }
    };
  • type
    A string value specfying the animation type. The value of the option affects the initial and target state of the widget. These states are specified via the from and to fields of the show, and hide configuration objects. The type object can take on the following values.

    NOTE: The structure of objects passed to from and to fields depends on the selected animation type.

    • "fade" - the widget opacity changes from 0 to 1 when the widget is shown, or from 1 to 0 when it is being hidden.
      The fields can take on a number from 0 to 1 that specifies the widget opacity.

      JavaScript
      show:{
          type: "fade",
          from: 0.1,
          to: 0.9
      }
    • "pop" - the widget scale changes from 0 to 1 when the widget is shown and from 1 to 0 when it is being hidden. You can also change the widget opacity during animation.

      The from and to fields can take on an object containing the following fields.

      • scale - a number from 0 to 1 specifying the widget scale
      • opacity - a number from 0 to 1 specifying widget opacity
      JavaScript
      show:{
          type: "pop",
          from: {
              scale: 0.1,
              opacity: 0.1,
          }
          to: {
              scale: 1,
              opacity: 0.9,
          }
      }
    • "slide" - when the widget appears, it moves from an initial point to the target point, and disappears in the same way.

      The from and to fields can take on an object containing the following fields.

      • opacity - a number from 0 to 1 specifying widget opacity
      • left(right), top(bottom) - a number specifying the position of the widget in pixels
      JavaScript
      show: {
          duration: 3000,
          type: "slide",
          from: {
              left: -300,
          }
      },
      hide: {
          duration: 3000,
          type: "slide",
          to: {
              left: 300,
          }
      }
    • "Custom" - If you assign this value to the type option, you can customize the initial and target widget state as you need.

      The from and to fields can take on an object with the fields corresponding to the CSS properties you want to animate.

      JavaScript
      show: {
          duration: 3000,
          type: "custom",
          from: {
              top: -350,
              width: 0,
              "background-color": "blue"
          },
          to: {
              top: 50,
              width: 80%,
              "background-color": "yellow"
          }
      },

Use Icon Library

When building PhoneJS applications, you can use a built-in icon library. This library provides a large number of icons for all platforms supported by the framework. You can look through this library in the simulator to the right.

Whatever PhoneJS widget you use, if it exposes the icon option, you can assign the name of a required icon from the library to it.

HTML
<div class="button" data-bind="dxButton: { text: 'Click me', icon: 'arrowdown' }"></div>

Extend Icon Library

To extend the built-in icon library, add the dx-icon-... CSS class to the style sheets that are used in your application. Set the icon name as the third part of the class name. For instance, the following class will be used to display the myicon icon.

CSS
.dx-icon-myicon
{
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAQAAAACj/
  OVAAAARElEQVRYw+3WKQ4AIAADMPb/R4PHIDgTOr/ULUstZxPgfbAvBAgEAoFAIPAhcPebChAIHIKmDQgEAoFA4E/
  g7JcCrk4DW5xoAVzaKL0AAAAASUVORK5CYII=) 0 0 no-repeat;
}

When an icon is set in this way, it can be applied to PhoneJS widgets in the same way as a built-in icon. This means that you can use the icon widget option, setting the name of your icon to it.

HTML
<div class="button" data-bind="dxButton: { text: 'Click me', icon: 'myicon' }"></div>

NOTE: We recommend that you use the Base64 type for icons when using them for PhoneJS widgets in this way, to reduce the number of requests and the amount of data transferred.

You can set a specific icon variant for different platforms. In this instance, add the dx-icon-... class under the dx-theme-... CSS class, where the latter defines one of the platforms supported by the framework.

CSS
.dx-theme-android .dx-icon-myicon
{
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAQAAAACj/
  OVAAAARElEQVRYw+3WKQ4AIAADMPb/R4PHIDgTOr/ULUstZxPgfbAvBAgEAoFAIPAhcPebChAIHIKmDQgEAoFA4E/
  g7JcCrk4DW5xoAVzaKL0AAAAASUVORK5CYII=) 0 0 no-repeat;
}
.dx-theme-ios.dx-version-major-5 .dx-icon-myicon, .dx-theme-ios.dx-version-major-6 .dx-icon-myicon
{
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAQAAAACj/
  OVAAAAbElEQVRYw+3XMQoAIQxE0YzswffmsRK2kbFZg/itVNBHRHBUxt7WNnvxjI5WV7xmPGlZVaHSVJhuwhyNqisEBAQEBAQE/
  GSaWTaRe/AXM83Yvy7TxN8BVdxSQED+FoCAgICAgIA3ZBqO9FiwA9kyEOwz5x38AAAAAElFTkSuQmCC) 0 0 no-repeat;
}

.dx-theme-ios.dx-version-major-7 .dx-icon-myicon
{
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAQAAABtnpmgAAAAZUlE
  QVRo3u3SsQkAIAwEQDOw0ziwFhZiY6OixX0VCDwXSNT0ZwIMDAwMDAwMDAwMDAzsJKyMsVfFvM9gYGBgYGBgYCvG1h0
  5wL6BeX4wMDAwMDCw27BbAQMDAwMDAwMDAwMDe5IGFJGKAcyLcs4AAAAASUVORK5CYII=) 0 0 no-repeat;
}    

In addition, consider providing a specific icon variant for differnet states of a widget (widget item). The following example shows how to provide an icon for a selected tab.

CSS
.dx-theme-ios.dx-version-major-7 .dx-tab-selected .dx-icon-myicon
{
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAA4CAQAAAACj/OVAAAAQElEQVRYw+3XsQ0AIAwDMPL/
  0TD0BEQ74OyRl0pVsldvAgQCgcAxsGoBAoFA4Pfg3ecK0JUCgUAg0CAFAoHAdzlK5VcBsySXawAAAABJRU5ErkJggg==) 0 0 no-repeat;
}

To see more examples of PhoneJS-specific CSS classes, research the style sheets that come with the product.

As an alternative to the CSS-defined icons, you can add a folder with custom icons to your application and use them via the widgets' iconSrc configuration option.

HTML
<div class="button" data-bind="dxButton: { text: 'Click me', iconScr: '/images/myicon.png' }"></div>