# Tip Calculator Demo

This tutorial is an overview of the Tip Calculator demo. The TipCalculator is a cross-platform mobile application that provides a fast and convenient way to calculate tips for a check. Inputting the sum from a check, users get the total tips due, as well as the totals and tips per person.

Technically, the TipCalculator is a simple single-screen application. It contains a single view based on an empty layout (with a single placeholder for the view). Follow this tutorial to learn how the view is implemented using the MVVM pattern: how a ViewModel is defined, how a View is designed using PhoneJS widgets and how Knockout is used to bind the View to the ViewModel.

The TipCalculator demo is located in the Demos/TipCalculator folder of the PhoneJS zip archive. In addition, you can download this demo from the GitHub resource. Go through the steps below to review what is inside.

Note that if you want to learn the basics on how to create applications using PhoneJS, start with the Your First Application and Data-Bound Application step-by-step tutorials. They discuss the main ideas required for building applications using PhoneJS.

## Home ViewModel

Open the home.js file from the views folder. It contains a function that returns the 'home' view's ViewModel. This function has the same name ("home") as the view, and is called when the view is shown.

JavaScript
```TipCalculator.home = function(params) {
//...
return {
billTotal: billTotal,
tipPercent: tipPercent,
splitNum: splitNum,

totalTip: totalTip,
tipPerPerson: tipPerPerson,
totalPerPerson: totalPerPerson,
totalToPay: totalToPay,

roundUp: roundUp,
roundDown: roundDown,

viewShown: viewShown
};
};```

The ViewModel represents an object whose fields bring values (data) for UI fields.

As you can see in the simulator's screen, there are three values that are specified by the end user. The ViewModel includes variables to store these input values.

• billTotal
A variable that stores the total sum from a check.

• tipPercent
A variable that stores the percentage value for the tips.

• splitNum
A variable the stores the number of people to divide the payment.

JavaScript
```var billTotal = ko.observable(),
tipPercent = ko.observable(DEFAULT_TIP_PERCENT),
splitNum = ko.observable(1);```

All these variables are declared as observables - Knockout objects that can notify subscribers about changes and can automatically detect dependencies. So, the variables mentioned always store the actual values entered to the UI fields bound to them.

The input variables are used to calculate the output. The ViewModel includes the following variables to store the results.

• totalTip
The sum of the tips based on the arranged tip percent.

• totalToPay
The sum of the total by the check and the tips.

• totalPerPerson
Totals for each person that takes part in the payment.

• tipPerPerson
Tips for each person that takes part in the payment.

All of these variables are declared as computed observables - they depend on one or more observables and will automatically update whenever any of these dependencies change.

The algorithm of the output calculation implies that there are three round modes.

JavaScript
```var ROUND_UP = 1,
ROUND_DOWN = -1,
ROUND_NONE = 0,
roundMode = ko.observable(ROUND_NONE);```

The totalToPay computed observable uses the current round mode in its calculation algorithm.

JavaScript
```var totalToPay = ko.computed(function() {
var value = totalTip() + billTotalAsNumber();

switch(roundMode()) {
case ROUND_DOWN:
if(Math.floor(value) >= billTotalAsNumber())
return Math.floor(value);
return value;

case ROUND_UP:
return Math.ceil(value);

default:
return value;
}
});```

The remaining computed observables are implemented in the following way.

JavaScript
```var totalTip = ko.computed(function() {
return 0.01 * tipPercent() * billTotalAsNumber();
});

var tipPerPerson = ko.computed(function() {
});

var totalPerPerson = ko.computed(function() {
return (totalTip() + billTotalAsNumber()) / splitNum();
});```

By default, the roundMode variable is set to ROUND_NONE. To set this variable to ROUND_UP or ROUND_DOWN, the following functions are implemented.

JavaScript
```function roundUp() {
roundMode(ROUND_UP);
}

function roundDown() {
roundMode(ROUND_DOWN);
}```

The roundMode variable must be set back to the ROUND_NONE value when one of the inputs changes, so that the outputs are recalculated without rounding the results. To be notified when the values of the billTotal, tipPercent and splitNum observables change, the subscribe() function is used.

JavaScript
```billTotal.subscribe(function() {
roundMode(ROUND_NONE);
});

tipPercent.subscribe(function() {
roundMode(ROUND_NONE);
});

splitNum.subscribe(function() {
roundMode(ROUND_NONE);
});```

The last ViewModel field that has not yet been described is viewShown. Read below to learn about its purpose and implementation.

## Home View

Open the home.html file from the views folder. It contains the HTML markup of the "home" view. This markup, together with the CSS styles used in it, form a View - the view's visual representation according to the MVVM pattern. Below you will see how a View is defined and bound to a ViewModel.

To indicate this markup as a View, the data-options attribute set to dxView is used.

HTML
```<div data-options="dxView : { name: 'home' }">
<div data-options="dxContent : { targetPlaceholder: 'content' }">
<!-- View contents does here-->
</div>
</div>```

A name for the View is specified using the name option of the markup configuration object.

Generally, an application's screen does not only include the view's markup. There can be a common markup used in all (several) screens. This markup is defined in the layout. In addition, the layout has a placeholder for a view. When displaying a screen, the view that is denoted in the current URL is inserted into the layout's placeholder.

As you can see in the code above, the "home" View is inserted into the "content" placeholder. The layout's name is not specified for the view specifically, as there is no reason to do this. This application consists of a single view and the layout in which this view is displayed is specified for the application object (read below). To learn more about views and layouts, how to define and specify them, refer to the Views and Layouts article.

The "home" view contains a toolbar at the top. Notice the "Tip Calculator" text in the center of the toolbar.

HTML
```<div data-options="dxView : { name: 'home' }">
<div data-options="dxContent : { targetPlaceholder: 'content' }">
<div data-bind="dxToolbar: { items: [{ align: 'center', text: 'Tip Calculator' }] }"></div>
<!-- ... -->
</div>
</div>```

The toolbar is the dxToolbar widget. This widget, like all widgets in this view, is supplied with PhoneJS. Each widget comes with styles for different platforms and devices. To learn more about widgets, refer to the UI widgets article.

To input the total sum from the check, a number box is added to the view.

HTML
```<div data-options="dxView : { name: 'home' }">
<div data-options="dxContent : { targetPlaceholder: 'content' }">
<!-- ... -->
<div class="dx-fieldset top-fieldset">
<div class="dx-field">
<div class="dx-field-label">Bill Total:</div>
<div id="billTotalInput" class="dx-field-value" data-bind="dxNumberBox: { value: billTotal, placeholder: 'Type here...', valueUpdateEvent: 'keyup', min: 0 }"></div>
</div>
</div>
</div>
</div>```

The number box is the dxNumberBox widget. The value that is input by an end user is assigned to the widget's value configuration option. This option is bound to the billTotal field of the view's ViewModel.

The dxNumberBox widget is added to a field set that is defined by the predefined stylesheets (dx-fieldset, dx-field, dx-field-label and dx-field-value) supplied by PhoneJS. The top-fieldset class is defined specifically for this application (see the index.css file).

To set the tip percentage and the number of persons by which to divide the payment, sliders are added.

HTML
```<div data-options="dxView : { name: 'home' }">
<div data-options="dxContent : { targetPlaceholder: 'content' }">
<!-- ... -->
<div class="dx-fieldset">
<div class="dx-field slider-container">
<div class="slider-title">Tip, %</div>
<div class="slider-body">
<div data-bind="dxSlider: { min: 0, max: 25, step: 1, activeStateEnabled: true, value: tipPercent }"></div>
</div>
<div class="slider-value" data-bind="text: Globalize.format(0.01 * tipPercent(), 'p0')"></div>
</div>
<div class="dx-field slider-container">
<div class="slider-title">Split:</div>
<div class="slider-body">
<div data-bind="dxSlider: { min: 1, step: 1, max: 10, activeStateEnabled: true, value: splitNum }"></div>
</div>
<div class="slider-value" data-bind="text: splitNum"></div>
</div>
</div>
</div>
</div>```

The sliders are the dxSlider widget. The value that is set by end users is assigned to the widget's value configuration option. This option is bound to the ViewModel's field (the tipPercent and splitNum fields).

To show the value that is set via a slider, a div element is associated with the ViewModel's field using Knockout text binding.

The slider-container, slider-title, slider-body and slider-value style classes are defined specifically for this application (see the index.css file).

To calculate the results using the "round up" or "round down" modes, two buttons are added.

HTML
```<div data-options="dxView : { name: 'home' }">
<div data-options="dxContent : { targetPlaceholder: 'content' }">
<!-- ... -->
<div class="round-buttons">
<div data-bind="dxButton: { text: 'Round Down', clickAction: roundDown }"></div>
<div data-bind="dxButton: { text: 'Round Up', clickAction: roundUp }"></div>
</div>
</div>
</div>```

The buttons are represented by the dxButton widgets. The function that must be executed when clicking a button is assigned to the clickAction option of the widget's configuration object. To learn more about actions, refer to the Actions article.

The round-buttons style class is defined specifically for this application (see the index.css file).

To present the results of calculation, a field set is added.

HTML
```<div data-options="dxView : { name: 'home' }">
<div data-options="dxContent : { targetPlaceholder: 'content' }">
<!-- ... -->
<div id="results" class="dx-fieldset">
<div class="dx-field">
<span class="dx-field-label">Total to pay</span>
<span class="dx-field-value" style="font-weight: bold" data-bind="text: Globalize.format(totalToPay(), 'c')"></span>
</div>
<div class="dx-field">
<span class="dx-field-label">Total per person</span>
<span class="dx-field-value" data-bind="text: Globalize.format(totalPerPerson(), 'c')"></span>
</div>
<div class="dx-field">
<span class="dx-field-label">Total tip</span>
<span class="dx-field-value" data-bind="text: Globalize.format(totalTip(), 'c')"></span>
</div>
<div class="dx-field">
<span class="dx-field-label">Tip per person</span>
<span class="dx-field-value" data-bind="text: Globalize.format(tipPerPerson(), 'c')"></span>
</div>
</div>
</div>
</div>```

To display the results, span elements are associated with the ViewModel's fields using Knockout text binding. To apply a currency format for the results, the format function from the globalize library is used.

To focus the Bill Total field when the view is shown, implement the viewShown function in the view's ViewModel.

JavaScript
```function viewShown() {
\$("#billTotalInput").data("dxNumberBox").focus();
}```

## Application Page

Open the index.html file. It represents the application page.

The application page contains links to the required libraries: PhoneJS, jQuery, Knockout and globalize. These libraries are contained in the js folder of the application project.

HTML
```<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="js/knockout-2.2.1.js"></script>
<script type="text/javascript" src="js/globalize.min.js"></script>
<script type="text/javascript" src="js/dx.phonejs.js"></script>```

The application page also includes links to the stylesheets required for the application. The stylesheets are contained in the css folder of the application project.

HTML
```<link rel="stylesheet" type="text/css" href="css/dx.common.css" />

Wherever the application runs on iOS, Android, Tizen or Windows Phone 8 platforms, the application looks native, because the corresponding styles are applied.

PhoneJS comes with a set of predefined layouts. Each layout is designed for different platforms and devices, so that the elements that the layout includes are arranged according to the guides of the corresponding platform. In the TipCalculator application, the "EmptyLayout" is used. This layout contains a view placeholder only, and is appropriate for this simple application. You can find links to the layout files in the application page as well.

HTML
```<script type="text/javascript" src="layouts/Empty/EmptyLayout.js"></script>

Finally, the application page contains links to the view files, the application css and the JavaScript files.

HTML
```<!-- App views -->
<script type="text/javascript" src="views/home.js"></script>
<!-- App -->
<script type="text/javascript" src="index.js"></script>```

The index.css file contains the style classes that are designed for this application. They are used in the view's markup.

The index.js file is the script that is executed when the page is loaded. See its description below.

The application page only contains the view's markup and layout. There is no additional markup in the application. See the page body.

HTML
```<body>
<div class="dx-viewport dx-ios-stripes"></div>
</body>```

## Application Object

Open the index.js file. It contains the script that is executed when the application page is loaded.

JavaScript
```window.TipCalculator = {};
\$(function() {
TipCalculator.app = new DevExpress.framework.html.HtmlApplication({
namespace: TipCalculator,
defaultLayout: "empty"
});
TipCalculator.app.router.register(":view", { view: "home" });
TipCalculator.app.navigate();
});```

As you can see in the code above, the HTMLApplication object is created, a format for the application's URL is registered and the default ("home") view is navigated to, when the application page is loaded.

The application object is created in the TipCalculator namespace. To specify the namespace for the application object, the namespace option of the configuration object is used. As you may have noticed, the home function, which is executed when the "home" view is loaded, is also declared in the TipCalculator namespace.

The default layout used for the application's view is specified using the defaultLayout option of the application's configuration object.

The navigate function, which is called after the application object is created, changes the application's URI using the registered format - to the following: "#home". When the browser's URL changes, the framework displays the "home" view. To learn more about navigation, refer to the Navigation and Routing article.