Build HTML5-Based Menu App for iPad with DHTMLX Touch

DHTMLX Touch support and development was discontinued when all DHTMLX components became adaptive.

In this tutorial, we will share some experience of using the DHTMLX Touch framework for building mobile web interfaces. You will learn how to use different components, arrange them on a page, set templates, add connections, and combine the components into a single interface. As an example, we will build a restaurant menu application for iPad (it can be used on other mobile devices but the sizes are optimized for the iPad screen resolution).

Now we should decide about the layout of interface elements for our application. There should be menu categories, a list of dishes in the category, and Order button. So, the application interface will consist of these three sections:

list of menu categories (pizza, pasta, drinks, etc) – placed on the left

list of menu items – on the right

total price counter and “Order” button – on the bottom left

When we place and configure the Layout component on the page, it will look like this:

Layout defines global structure of the interface. Later we’ll add other components in the Layout cells, and connect them with each other. According to the scheme we’ve defined for our menu app, we need a Layout with 2 columns and 2 rows for the left column.

Layout is created by dhx.ui({}) construction. To set columns, you need to define “cols” array. If you need to arrange elements vertically one by one, use rows. The Layout structure for our menu interface will be:

dhx.ui({
cols:[{rows:[{...},{...}]},{...}]});

If we don’t set width and height for columns and rows, their sizes will be equal. However, we need the left column to be more narrow than the right one. Also, height of the rows in the left column should be different. Therefore, we need to define the sizes manually.

We will initialize Layout from the dhx.ready() method, since the component should be initialized when the page is completely loaded:

As you can see, an item in menu categories list contains 4 properties:

id

Img

Name

Description

Creating Template for DataView

Now we need to define a template for ‘menu category’ item and set width, height, margin and padding for it. These settings will differ from the default ones, so we should define a new item type for DataView. Let’s create HTML template of a new type, which will look like this:

type – the name of used type. The type that we’ve just created is “menu”.

id – a view id. It’s required if you need to manipulate with the view (get the view object). We’ll need the id to filter menu items in the right column when menu category is selected.

url – the URL to a datasource.

datatype – type of data (can be XML, JSON, or CSV).

Finally, we can move to the dataview style. We have defined how data properties are represented in the menu template, but we also need to set a background color and rounded borders for dataview items. Besides, selected and unselected items should have different styles:

In the next step we’ll create a list of menu items that will be displayed in the right column of the Layout.

STEP 3 – Menu Items

As well as in case of menu categories, we can choose between DataView, List and PageList to display menu items on the right. All these components, or views, fit our purpose, but we’ll choose PageList because it supports scrolling items one by one and controls the position of an item on the page. It means, if user scrolls through the items, the scroll will stop and display the full view of the item.

Again, data will be loaded from XML file. Each data item will contain the following properties:

id – item id

Img – image for the menu item

Name – item name

Description – item description

Price – item price

Count – number of odered items (0 initially)

Group – name of the menu category to which this item relates. In the 5th Step we’ll use this property for filtering.

There are three parameters for each menu item: image, name, and description. There also should be a button for ordering this item, and we shouldn’t forget about the possibility to exclude an item from the order.

Ordering features will be implemented in the last steps when the menu is associated with the order section. In this step, we’ll just create a list of menu items. A menu item will look like this:

The PageList component, which we’re using to display menu items, inherits CSS classes from the List view. Therefore, we will need to define CSS classes for the List.

By default the List, like any other view of DHTMLX Touch, has white background. Therefore, we need to redefine background for the list items, and set additional background for selected items. Also, text in the List items is single-lined by default and we need it to be multi-lined, so we’ll redefine white-space property too:

.dhx_list_item{
white-space: normal;
font-weight:normal;}

.dhx_list_content_item{
background: #e9d4b5;}

.dhx_list_content_item_selected{
background: #fffcd0;}

Some notes about these classes:

dhx_list_item class is applied to items of all List instances on the page. There is only one List instance in our layout, so we can set it safely. In addition, this class is applied to both unselected and selected items.

dhx_list_content_item class is applied only to the List instance that have type “content” in “css” property (in type “submenu” we have set css:”content”).

dhx_list_content_item_selected differs from the previous class because it is applied only to selected items.

STEP 4 – Landscape and Portrait Modes

Our menu application will be mostly adjusted to iPad screen size. The screen of the iPad (and other touch devices) can be switched from portrait to landscape mode. We need consider both these modes in our Layout, which works as a container for other components.

We’ll set the fixed width for the left column which contains menu categories. Then we need to change the sizes of the right column and template for the PageList to ensure a correct look of the application in both portrait to landscape modes.

For this reason, we’ll create two views of the menu list: “landscape”, which have been already described above:

Background color and some other properties are defined in the CSS classes that are associated with “css” property of the PageList type. Both “landscape” and “portrait” types will have some common properties. Therefore, we are creating an object that contains common properties and then extend a certain type with properties defined in this object.

pagelist_type ={
css:"content",margin:0,padding:0}

To add these properties to “landscape” and “portrait” objects, call dhx.extend method:

Now both types have been defined and we need to set “orientationchange” event listener that will change the type of menu list according to the device orientation.

Changing List Type

Screen mode can be checked by window.orientation property that indicates whether the screen is in portrait or landscape mode. If window.orientation returns 0 or 180, we need to set “portrait” type, and if it is 90 or -90, the type should be “landscape”.

To redefine configuration property of any view, you may call define method. And in this case, we’ll need the list id (“submenu”). $$(“submenu”) returns the object of menu list, and we then can apply methods to it. For example, $$(“submenu”).define(“type”,”portrait”).

Here is the complete function that sets appropriate type and adjusts the Layout sizes:

When the screen of the device changes orientation, browser window fires ‘orientationchange’ event. We are using DHTMLX API to set event listener – dhx.event(object,eventName,handler):

dhx.event(window,"orientationchange", orientation);

So, our menu will be properly displayed in both portrait and landscape modes.

STEP 5 – Linking Categories and List

Since the restaurant menu may contain a large number of different items/dishes, in our application we’ll filter and display them by categories (pizza, pasta, drinks, etc.). In the right column we’ll show the list of items (the view with “submenu” id) that belong to a menu category selected from the list in the left column (the view with “menu” id).

There are two possible ways to implement this functionality. The first one is to set onItemClick event handler for the “menu” and call filter method for the “submenu”. However, in this tutorial we want to demonstrate the other way – linking views by DataProcessor.

In the DataProcessor configuration we need to define the master view. It will be “menu”, since the list of menu items displayed in “submenu” depends on the category selected by user in “menu”.

var dp =new dhx.DataProcessor({
master:$$('menu')});

Then we need to call link() method to associate master and linked views with each other. Views can be linked by some property, for example, “Group” property of “submenu” view relates to “Name” property of “menu”: “Pasta”, “Pizza”, “Drinks” or “Coffee”.

In order to filter the list by default we set “onXLE” event handler for master view and select one of its items:

$$("menu").attachEvent("onXLE",function(){this.select(2);})

Actually linking views by DataProcessor solves the problem of asynchronous loading of two different data sources, because “onXLE” event is called after datasource of a certain component has been loaded to the client side.

In our example we need to filter the menu items only when data for both components – “menu” and “submenu” – has been loaded to the browser. If views are linked by DataProcessor, the loading process is managed by inner methods and we don’t have to worry about asynchronous loading.

STEP 6 – Adding Order Button

Now let’s add an order confirmation section to our menu. We’ll place it in the bottom row of the left column of our Layout. It will contain the total order price and Order button. This is how our order pane will look:

We will use “template” view, as we need to display only one data item with total price. This view will contain the following properties:

view – “template”

id – “order”

css – here we’ll define the CSS class for view, since we need to set background color and remove view borders

template – template that defines how total price counter and button will look

data – data object for the template

height – row hieght

In our previous steps we have used HTML templates. However, a template can also be defined by JavaScript function that takes data object as a parameter. So, now we’ll use this second approach:

Now, when all interface elements have taken their places, we should add a logic for making an order. For that we need to associate the menu list and order view. So, let’s move to the last step.

STEP 7 – Improving Menu Templates and Setting Event Handlers

Changing “Portrait” and “Landscape” Types

In the steps 3 and 4 we have created “landscape” and “portrait” types for the list of menu items. Now we need to modify them a bit. Icon in the right part of the menu item template should be clickbable and display the number of ordered items. Besides, there should be a button to decrease the number of ordered items.

These templates differ from the templates that have been created in the 3th and 4th steps by {common.count()} and {common.state()} constructions (here common represents a view type).

{common.state()} is a result which is returned by state method of a list type. count() method returns “+” or number of ordered items, state() returns empty string or HTML container that will be used to decrease the number of ordered items.

“landscape” and “portrait” types need count() and state() methods. We are defining these methods in the object which properties are inherited by both types:

We need to set onclick event listener to the div container with “buy_outside” CSS class. This listener will add a menu item in the order. In the “landscape” and “portrait” types we have defined count() method that returns value of this container. This value depends on Count property of data items, number of ordered items. So, in the event handler we need to increase Count property and redraw menu item to display data modifications. Also, we may highlight ordered item by select() method.

The DHTMLX Touch library provides a ready solution to set onclick event listener – on_click object. You need to add className of a necessary HTML container into this object and set event handler as a property value:

$$("submenu").on_click["buy_outside"]=function(e){/*id of the data item by event object*/var id =this.locate(e);/*data item by its id*/var data =this.get(id);/*incresing number of ordered items*/if(data.Count==99){return;}else{
i = parseInt(data.Count,10);
data.Count= i+1;}

/*If an item is already ordered, redraw it (apply count).
In the other case, the item is selected (selection causes redrawing)*/if(this.isSelected(id))this.refresh(id);elsethis.select(id,true);returntrue};

A similar approach can be used for the container with “buy_dec_outside” className which is defined in the state() method of list types. Its onlick listener will remove menu item from the order:

$$("submenu").on_click["buy_dec_outside"]=function(e){/*id of the clicked item by event*/var id =this.locate(e);/*decrease number of ordered items*/var data =this.get(id);
data.Count--;

/*changing the total price of the order*/var currentOrder = $$("order").data;
$$("order").data.total-= parseInt(data.Price,10);
$$("order").render();

/*If the last instance of the item is removed from an order, its selection is cleared.
In the other case, it is refreshed*/if(!data.Count)this.unselect(id);elsethis.refresh(id);};

Now items can be placed in the order and removed, if needed. The total price is displayed above the Order button.

Finally, our restaurant menu application is ready. Its sizes are configured mostly for iPad, but it will also run on other touch devices and in WebKit browsers. Again, you can download the menu app we’ve just built here, and study the sources.

Comments

The data items should contain taxes property – Step 3. And you need to consider it in templates, please see Step 3 and 4. Also, you need to add it in calculation of total order which is described in Step 7.

This is outside the topic of this tutorial. We just showed how to build the client-side part of mobile web app with DHTMLX Touch.
If interested, we provide custom development services and can create an app based on your requirements.

Ted, the issue might be caused by caching. To solve the issue, try to add the following random parameter to the url:
…
url:”xml/menu.xml?rs=”+(new Date()).valueOf(),
…
url:”xml/content.xml?rs=”+(new Date()).valueOf(),

Curt, unfortunately we do not have a ready demo. But we will try to describe the idea of possible solution.
You can put a “list” or “dataview” view as a row into the left layout (sample for the list view – samples/04_list/01_init.html). The list will show selected items and updated each time you change order. Both list and dataview have add(), remove() and update() methods that can be used for list updating.