UI Widgets

An HTML JS widget is a visual component rendered on a page. Typically, the widget is bound to data and provides user interaction. PhoneJS provides a big library of UI widgets. These widgets come with CSS stylesheets for each platform. When using these widgets in PhoneJS applications, the framework automatically applies the appropriate stylesheets, which changes widgets look and feel to match the platform they are used on. So 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 viewRendered 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 {
        viewRendered: 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() like 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, the "Dependency Tracking" feature offered by Knockout is rather useful. 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>

Widget 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 a view is displayed.

Customize Widget Item Appearance

The PhoneJS framework includes widgets intended to display multiple elements of the same type (dxList, dxGallery, dxTileView, etc.). If you need to display a collection item as a string value, assign the required array or another data source object to the dataSource configuration option of the widget. In this case, the widget item should be either a simple value (e.g., a string or a number), or an object containing one of the following fields.

  • text - specifies the text displayed within a container element of the item, and encodes all HTML escape characters contained in the text
  • html - specifies the HTML code displayed within a container element of the item

If an item object has a specific set of fields, use the jQuery or Knockout approach to specify the structure of the HTML element representing the item.

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

HTML
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
    });
});

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 Approach

To specify the widget item structure using the Knockout approach, create an HTML container element within the widget and apply the dxTemplate markup option to this element.

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>

You can specify a template for group header items of the dxList widget that display a grouped list. Create a template element as shown in the example 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.

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. Therefore, to get an option value, get the value of the corresponding ViewModel field. To change an option value dynamically during application flow and update the widget in response to the option change, utilize observables.

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-bezier(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 specifying 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 (from 1 to 0) when the widget is shown (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 (from 1 to 0) when the widget is shown (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"
          }
      },