Your First Application

This tutorial will walk you through creating your first PhoneJS application. It will be a basic HTML JS single-page application. Along the way, you will define two views by creating HTML templates and ViewModels. In addition, you will add simple actions to move between these views.

View on GitHub Watch Video

Code Preview

Applications created using PhoneJS are single-page applications (SPA). This means that an entire application can fit on a single web page. The page content is taken from a server only once. After this, the application interacts with the server using AJAX.

Here is the code of the application that you will develop while going through the tutorial.

<!DOCTYPE html>
<head>
    <meta charset="utf-8" />
    <title>Hello World</title>
    <link rel="stylesheet" type="text/css" href="/css/dx.common.css" />
    <link rel="stylesheet" type="text/css" href="/css/dx.ios.default.css" />
    <link rel="stylesheet" type="text/css" href="/css/dx.android.holo-dark.css" />
    <link rel="stylesheet" type="text/css" href="/css/dx.tizen.black.css" />
    <link rel="stylesheet" type="text/css" href="/css/dx.generic.light.css" />
    <link rel="stylesheet" type="text/css" href="/css/dx.win8.black.css" />
    <script type="text/javascript" src="/js/jquery-2.0.3.min.js"></script>
    <script type="text/javascript" src="/js/knockout-3.0.0.js"></script>
    <script type="text/javascript" src="/js/globalize.min.js"></script>
    <script type="text/javascript" src="/js/dx.phonejs.js"></script>
    <!-- Layouts -->
    <script type="text/javascript" src="/layouts/Simple/SimpleLayout.js"></script>
    <link rel="stylesheet" type="text/css" href="/layouts/Simple/SimpleLayout.css" />
    <link rel="dx-template" type="text/html" href="/layouts/Simple/SimpleLayout.html"/>    
    <script type="text/javascript">
        window.AppNamespace = {};
        $(function () {       
            AppNamespace.app = new DevExpress.framework.html.HtmlApplication({
                namespace: AppNamespace,
                navigationType: "simple"
            });
            AppNamespace.app.router.register(":view/:name", { view: "home", name: '' });
            AppNamespace.app.navigate();
        });
        AppNamespace.home = function () {
            var viewModel = {
                message: ko.observable('Welcome!'),
                name: ko.observable(''),
                sayHello: function () {
                    this.message("Hello " + this.name() + '!');
                },
                greet: function () {
                    AppNamespace.app.navigate("greeting/" + this.name());
                }
            };
            return viewModel;
        };
        AppNamespace.greeting = function (params) {
            var viewModel = {
                message: ko.observable('Hello ' + params.name + '!'),
            };
            return viewModel;
        };
    </script>
</head>
<body>
    <div data-options="dxView : { name: 'home', title: 'Home' } " >
        <div data-options="dxContent : { targetPlaceholder: 'content' } " >
            <h1 data-bind="text: message"></h1>
            Enter your name: <div data-bind="dxTextBox: { value: name }" style="width: 200px"></div>
            <div data-bind="dxButton: { text: 'Say Hello', clickAction: sayHello }"></div>
            <div data-bind="dxButton: { text: 'Greet', clickAction: greet }"></div>
        </div>
    </div>
    <div data-options="dxView : { name: 'greeting', title: 'Greeting' } " >
        <div data-options="dxContent : { targetPlaceholder: 'content' } " >
            <h1 data-bind="text: message"></h1>
        </div>
    </div>
</body>
</html>

Refer to the information below to implement the above-mentioned code.

Create an Application

Start with creating an application.

  • Create an HTML file and give it the "index.html" name.
  • In the created file, reference the libraries from the lib | js folder of your PhoneJS zip archive.

    NOTE: The PhoneJS library must be referenced last.

  • To turn your simple HTML page into an application, create an HtmlApplication object within the document.ready event handler or the jQuery "$()" function. The HtmlApplication object will control the application life cycle and display views.
  • Specify a routing format for the application's navigation and call the navigate method of the HtmlApplication object to navigate to the first view.

Here is the code in the index.html file.

HTML
<!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <title>My First Application</title>
            <script type="text/javascript" src="/js/jquery-2.0.3.min.js"></script>
            <script type="text/javascript" src="/js/knockout-3.0.0.js"></script>
            <script type="text/javascript" src="/js/globalize.min.js"></script>
            <script type="text/javascript" src="/js/dx.phonejs.js"></script>
            <script type="text/javascript">
                window.AppNamespace = {};
                $(function () {
                    AppNamespace.app = new DevExpress.framework.html.HtmlApplication({
                        namespace: AppNamespace
                    });
                    AppNamespace.app.router.register(":view", { view: "home" });
                    AppNamespace.app.navigate();
                });
            </script>
        </head>
        <body></body>
    </html>

Note that a starting view wasn't specified within the navigate method, but the "home" view was set as the default view for the application's router.

Create a View

To add the first view to your application, define an HTML template that will be used to display this view.

  • Add a div element with the data-options attribute set to dxView.
  • Give a name to the view by assigning a configuration object with the name option specified. The specified name will be used to identify the view.
HTML
<body>
    <div data-options="dxView: {name: 'home'}">
        Hello World!
    </div>      
</body>

The framework follows the Model View ViewModel (MVVM) pattern to provide a clean separation of the user interface from the business logic. An application consists of a set of Views defined by an HTML5 markup and the accompanying resources (images and CSS3 styles). Views can be bound to the corresponding ViewModels via the Knockout JavaScript library. The ViewModel is basically your custom JavaScript code, which is responsible for providing data from the Model to the View taking into account different user interactions. The Model is represented by the data that you can obtain from virtually anywhere. So, you may choose to connect to remote data sources via AJAX requests, bind to JavaScript objects or even use HTML5 local storage.

Actually, the HTML template presented above is a View of the "home" view in terms of the MVVM pattern, because no css classes are used in this template. Read further to learn how to bind this View to a ViewModel.

Bind a View to ViewModel

Bind a view element to the ViewModel's field.

  • Associate a JavaScript function with the View and this function will be called when the View is used. This function must have the same name as the View. In addition, it must be declared in the application's namespace and return an object. This object is a ViewModel for the View.
  • Add the message field to the ViewModel object. Set this field to "Welcome!"
  • In the view's HTML template, replace the simple "Hello World" string with the h1 element bound to the message field of the ViewModel via Knockout.
JavaScript
AppNamespace.home = function () {
    var viewModel = {
        message: 'Welcome!'
    };
    return viewModel;
};
HTML
<div data-options="dxView : { name: 'home'} " >
    <h1 data-bind="text: message"></h1>
</div>

Update ViewModel Field Values Dynamically

Add a text box to the "home" view to concatenate the "Welcome!" text with the entered text at runtime.

  • Make the ViewModel's message field observable.
  • Add a text box to the view's HTML template to allow an end user to input the desired value.
  • Add an observable name field to the ViewModel and bind the text box' value to this field.
  • Add a button to the view's HTML template to update the value of the ViewModel's message field when the name field is changed.
HTML
<div data-options="dxView: {name: 'home'}">
    <h1 data-bind="text: message"></h1>
    Enter your name: <div data-bind="dxTextBox: { value: name }" style="width: 200px"></div>
    <div data-bind="dxButton: { text: 'Say Hello', clickAction: sayHello }"></div>
</div>
JavaScript
AppNamespace.home = function () {
    var viewModel = {
        message: ko.observable('Welcome!'),
        name: ko.observable(''),
        sayHello: function () {
            this.message("Hello " + this.name() + '!');
        }
    };
    return viewModel;
};

As you can see in the code above, we used the dxTextBox and dxButton widgets from the PhoneJS widget library. These widgets are supplied with styles for each platform so that your application looks native on any platform. These styles are collected in platform-specific css files that are located in the lib | css folder of the PhoneJS zip archive. Link the required css files in the following way.

HTML
<head>
    <link rel="stylesheet" type="text/css" href="dx.common.css" />
    <link rel="stylesheet" type="text/css" href="dx.ios.default.css" />
    <!--...-->
</head>

Add Navigation between Views

Add one more view called "greeting" and display it instead of the "home" view on the page when clicking a button.

  • Add an HTML template for the "greeting" view as you did above.
  • Add a ViewModel for the "greeting" view as you did above.
  • Add the h1 element to the HTML template and bind it to the ViewModel's message field.
  • Add the dxButton widget to the HTML template and bind its clickAction option to the built-in registered function "#_back". This function returns end users to the previously shown view.
  • Add the greet function to the "home" view's ViewModel. In this function, call the navigate method of the HtmlApplication object, passing "greeting" as a parameter. "greeting" is the name of the view to navigate to. This parameter value conforms to the routing format that you specified for the application's routing above.
  • Add the dxButton widget to the "home" view's HTML template and bind its clickAction option to the ViewModel's greet function.
HTML
<div data-options="dxView: {name: 'home'}">
    <h1 data-bind="text: message"></h1>
    Enter your name: <div data-bind="dxTextBox: { value: name }" style="width: 200px"></div>
    <div data-bind="dxButton: { text: 'Say Hello', clickAction: sayHello }"></div>
    <div data-bind="dxButton: { text: 'Greet', clickAction: greet }"></div>
</div>
<div data-options="dxView : { name: 'greeting'} " >
    <h1 data-bind="text: message"></h1>
    <div data-bind="dxButton: { text: 'Go back', clickAction: '#_back' }"></div>
</div>
JavaScript
AppNamespace.home = function () {
      var viewModel = {
          message: ko.observable('Welcome!'),
          name: ko.observable(''),
          sayHello: function () {
              this.message("Hello " + this.name() + '!');
          },
          greet: function () {
              AppNamespace.app.navigate("greeting");
          }
      };
      return viewModel;
  };
  AppNamespace.greeting = function (params) {
      var viewModel = {
          message: 'Hello!',
      };
      return viewModel;
  };

Add a Common Page Layout

Add a toolbar to the "home" and "greeting" views and provide a visual transition effect when one view changes another. In PhoneJS applications, the elements that are common for several views are defined within a page layout. PhoneJS comes with a set of ready-to-use layouts that are characterised by the presence and type of a navigation control. In this application, a navigation control is not required. However, to add a common toolbar, the predefined "simple" layout is appropriate.

  • Link the SimpleLayout.html, SimpleLayout.css and SimpleLayout.js files in the application page. You can find all the layouts, including the "simple" one, in the lib | layouts folder of the PhoneJS zip archive.
  • Indicate that the "home" and "greeting" views must be shown in the "content" placeholder of the "simple" layout by wrapping the view's markup by a div element with the data-options attribute set to dxContent. Specify the name of the placeholder by setting the targetPlaceholder option to "content".
  • Since the toolbar of the "simple" layout can display a view's title, specify the title markup option of the dxView components.
  • To use the "simple" layout for the views, specify the application's navigation type at which the "simple" layout markup is used. To do this, set the application's navigationType configuration option to "simple".
  • Since a Back button is added to the built-in layouts automatically, when there is a previously shown view, you can remove the Back button that was added manually.
HTML
<!-- Layouts -->
<script type="text/javascript" src="/layouts/Simple/SimpleLayout.js"></script>
<link rel="stylesheet" type="text/css" href="/layouts/Simple/SimpleLayout.css" />
<link rel="dx-template" type="text/html" href="/layouts/Simple/SimpleLayout.html"/>
JavaScript
 
AppNamespace.app = new DevExpress.framework.html.HtmlApplication({
    namespace: AppNamespace,
    navigationType: "simple"
});
HTML
<div data-options="dxView: {name: 'home', title: 'Home'}">
    <div data-options="dxContent : { targetPlaceholder: 'content' } " >
        <h1 data-bind="text: message"></h1>
        Enter your name: <div data-bind="dxTextBox: { value: name }" style="width: 200px"></div>
        <div data-bind="dxButton: { text: 'Say Hello', clickAction: sayHello }"></div>
        <div data-bind="dxButton: { text: 'Greet', clickAction: greet }"></div>
    </div>
</div> 
<div data-options="dxView : { name: 'greeting', title: 'Greeting'} " >
  <div data-options="dxContent : { targetPlaceholder: 'content' } " >
      <h1 data-bind="text: message"></h1>
  </div>
</div>

Before a view is shown, its HTML template is merged to the "content" placeholder of the "myLayout" layout to get a total markup of the view.

Pass a Parameter to a View

Pass the text entered in the "home" view to the "greeting" view and concatenate it to the "Hello" string.

  • Add the name parameter to the application's routing format, and set the parameter's default value to an empty string.
  • In the "home" ViewModel's greet function, expand the parameter passed in the navigate function with the value of the name field (the value entered in the text box). This will conform to the new routing format.
  • Make the message field of the "greeting" ViewModel observable. Set this field to the text passed as the parameter from the view's URL.
JavaScript
AppNamespace.app.router.register(":view/:name", { view: "home", name: '' });
JavaScript
greet: function () {
    AppNamespace.app.navigate("greeting/" + this.name());
}
JavaScript
AppNamespace.greeting = function (params) {
    var viewModel = {
        message: ko.observable('Hello ' + params.name + '!'),
    };
    return viewModel;
};