Advertisement

Build a Titanium Mobile Pizza Ordering App: Order Form Setup

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →
This post is part of a series called Build a Titanium Mobile Pizza Ordering App.
Build a Titanium Mobile Pizza Ordering App: Topping Selection
Build a Titanium Mobile Pizza Ordering App: Order Completion

Welcome to the third installment in our series demonstrating how to build a pizza ordering application with Titanium Mobile. In this tutorial, we'll be creating the "Submit Your Order" screen.


Step 1: The Details Window

Now that the user is able to select and deselect toppings, we need to allow the user to actually submit an order. Let's start by modifying the details click event inside toppings.js:

details.addEventListener('click',function(e){
	var pizzaInfo = [];
	for (var i = 0; i < toppings.length; i++)
	{
		if (toppings[i].container != null)
		{
			pizzaInfo.push(toppings[i].title);
		}
	}
	Ti.App.fireEvent('details',{crust:win.crust,path:win.path,toppings:pizzaInfo});
});

Now when you hit the details button in the toppings window the code above will loop through our giant array of toppings and check the container property for each array item. If the item isn't null, it will add it to our temp array, called pizzaInfo. After the loop finishes, we will fire a new custom event called details. We will pass three parameters to this event:

  • The selected crust.
  • The image path to the selected crust.
  • The selected toppings (i.e. the temp array called pizzaInfo).

Step 2: Coding the openDetails Event

We need to modify our main.js file to listen for our custom event, so go ahead and open that file now. You are also going to add a new method called openDetails to the code:

var win             = Ti.UI.currentWindow;

//-- Create the sub windows
var crusts          = Ti.UI.createWindow();
var toppings        = Ti.UI.createWindow();
var details         = Ti.UI.createWindow();

//-- We set the background here since this wont change
win.backgroundImage = '../images/bg_main.png';

//-- Include our clock
Ti.include('../includes/clock.js');

//-- This method will close the crusts/details window and open the toppings window
function openToppings(e)
{
	crusts.close();

	toppings.url            = 'toppings.js';
	toppings.crust          = e.crust;
	toppings.path           = e.path;
	toppings.returnToppings = e.toppings;
	
	toppings.open();
}

//-- The method will close the toppings window and open the crusts window
function openCrust(e)
{
	toppings.close();
	//-- If the event has a crust property, that means the user hit cancel once in the toppings window
	if (e.crust)
	{
		crusts.crust = e.crust;
	}
	crusts.url = 'crusts.js';
	crusts.open();
}

//-- This method will close the toppings window and open the details window
function openDetails(e)
{
	toppings.close();
	
	details.crust       = e.crust;
	details.path        = e.path;
	details.toppings    = e.toppings;
	details.url         = 'details.js';
	
	details.open();
}

//-- Have our app listen for our custom events
Ti.App.addEventListener('toppings',openToppings);
Ti.App.addEventListener('cancelToppings',openCrust);
Ti.App.addEventListener('details',openDetails);

openCrust({});

Okay, your main.js file should now match the code above. In the above code, we added a new event listener at the bottom called details and when the app receives that event, we want to call the openDetails method. In the openDetails method, we first close the toppings window. We then set some properties on the details window with the values from the event we passed in toppings.js. We also set the URL property to details.js and finally call the open method.


Step 3: Creating the Details Form

We need to make a new javascript file called details.js and save it in the main_windows folder. What we want to do in this file is add three text fields:

  • Name
  • Address Line 1
  • Address Line 2

NOTE: In a real-world application, we would obviously have more fields, but for the sake of this tutorial we will have only created three fields.

We are also going to have a summary of the pizza the user has ordered with a submit order button. Let's start with the interface for this:

var win      = Ti.UI.currentWindow;
var orderReq = Titanium.Network.createHTTPClient();

//-- Name Text Field
var names = Titanium.UI.createTextField({
	color:'#336699',
	top:100,
	left:10,
	width:300,
	height:40,
	hintText:'Name',
	backgroundImage:'../images/textfield.png',
	paddingLeft:8,
	paddingRight:8,
	keyboardType:Titanium.UI.KEYBOARD_DEFAULT,
	returnKeyType:Titanium.UI.RETURNKEY_NEXT,
	suppressReturn:false
});

//-- Address1 Text Field
var address1 = Titanium.UI.createTextField({
	color:'#336699',
	top:140,
	left:10,
	width:300,
	height:40,
	hintText:'Address 1',
	backgroundImage:'../images/textfield.png',
	paddingLeft:8,
	paddingRight:8,
	keyboardType:Titanium.UI.KEYBOARD_DEFAULT,
	returnKeyType:Titanium.UI.RETURNKEY_NEXT,
	suppressReturn:false
});

//-- Address2 Text Field
var address2 = Titanium.UI.createTextField({
	color:'#336699',
	top:180,
	left:10,
	width:300,
	height:40,
	hintText:'City, State, Zip Code',
	backgroundImage:'../images/textfield.png',
	paddingLeft:8,
	paddingRight:8,
	keyboardType:Titanium.UI.KEYBOARD_DEFAULT,
	returnKeyType:Titanium.UI.RETURNKEY_DEFAULT
});

//-- Listen for the next click on the key board
names.addEventListener('return',function(){address1.focus();});
address1.addEventListener('return',function(){address2.focus();});

win.add(names);
win.add(address1);
win.add(address2);

//-- This method makes a nice formatted summary of the users order
function getFormattedPizza()
{
	var text = win.crust + ' pizza with:\n';
	if (win.toppings.length == 0)
	{
		text += '&bull; Plain (cheese pizza)\n';
	}
	else
	{
		for (var i = 0; i < win.toppings.length; i++)
		{
			text += '&bull; ' + win.toppings[i] + '\n';
		}
	}
	return text;
}

//-- Are formatted text field
var pizzaInfoText = Ti.UI.createLabel({
	text:getFormattedPizza(),
	font:{
		fontFamily:'Verdana',
		fontSize:14
	},
	color:'#fff',
	shadowColor:'#333',
	shadowOffset:{x:1,y:1},
	textAlign:'left',
	width:Ti.Platform.displayCaps.platformWidth,
	height:160,
	top:210,
	left:10
});
win.add(pizzaInfoText);

//-- Order Button
var order = Ti.UI.createButton({
	width:137,
	height:75,
	backgroundImage:'../images/order.png',
	top:385,
	left:165,
	opacity:0
});

//-- Cancel Button
var cancel = Ti.UI.createButton({
	width:137,
	height:75,
	backgroundImage:'../images/cancel.png',
	top:385,
	left:10,
	opacity:0
});

//-- If android OS, use the image property instead of backgroundImage (Ti SDK bug)
if (Ti.Platform.osname == 'android')
{
	order.image = '../images/order.png';
	cancel.image = '../images/cancel.png';
}
win.add(order);
win.add(cancel);

//-- Fade the order button in
order.animate({
	opacity:1,
	duration:500
});

//-- Fade the cancel button in
cancel.animate({
	opacity:1,
	duration:500
});

The above block of code may look scary, but really it is quite simple. We start by defining our win variable as well as our orderReq variable. The orderReq variable will handle our request out to our PHP file which we will cover in the next tutorial of this series.

We then define our three text fields and give them some simple properties. We add a return event listener on the text fields so when you hit next on the keyboard, it jumps to the next text field. We make a label called pizzaInfoText and set its text property to our getFormattedPizza method. This method will return a formatted list of our chosen crust and toppings. If the user selected no toppings, we will display the crust type and a simple cheese pizza. We've also made our order and cancel buttons and faded them in. Your interface should look like this now:


Step 4: Coding the Cancel Button

So you're in the submit order screen and you decide you want to remove mushrooms from your topping list. Well, no problem! The app already knows the toppings you currently have selected, so we will simply pass that temp array back to toppings.js and recheck the toppings. We first need to add an event listener to our cancel button. Scroll to the bottom of your details.js file and add this:

//-- Cancel button event. Goes back to the toppings window and remembers the users selections
cancel.addEventListener('click',function(){
	Ti.App.fireEvent('cancelDetails',{crust:win.crust,path:win.path,toppings:win.toppings});
});

We are firing yet another custom event, this time called cancelDetails, and again we pass three parameters:

  • The selected crust.
  • The image path to the selected crust.
  • The selected toppings (i.e. our temp array).

Step 5: Code the cancelDetails Event

Let's go back to main.js. We need to add a new event listener. Add the following to the end of our event listeners.

Ti.App.addEventListener('cancelDetails',openToppings);
</pre>
<p> Now we already have an <code>openToppings</code> method. We do however need to modify it. </p>
<pre name="code" class="javascript">
//-- This method will close the crusts/details window and open the toppings window
function openToppings(e)
{
	if (e.toppings)
	{
		details.close();
	}
	else
	{
		crusts.close();
	}

	toppings.url            = 'toppings.js';
	toppings.crust          = e.crust;
	toppings.path           = e.path;
	toppings.returnToppings = e.toppings;
	
	toppings.open();
}

So, with our modified method, we do a check for the toppings property tied to the event. If it isn't null, we want to close the details window. If it is null, we want to close the crust window. We still add our custom properties and then open our toppings window.


Step 6: Checkbox Preselection

When we go back we want to preselect the checkboxes of the topping we previously chose. We also want to add the toppings to the pizza visually. Open up the toppings.js file and scroll down to the createToppingsList method. The difference between your current one and the one below is if win.returnToppings isn't null, it will loop through our larger toppings array and compare it to our temp array. If they match up, recheck the checkbox, add the visual to the crust, and increase our toppings count.

/*
This method creates the topping list. Since iOS doesn't have checkmark components, I made my own using a view, a button and swapping out the background image
*/
function createToppingsList()
{
	scrollView.opacity = 0;
	scrollView.top = 155;
	scrollView.height = 120;
	scrollView.contentWidth = Ti.Platform.displayCaps.platformWidth;
    scrollView.contentHeight = 'auto';
    scrollView.showVerticalScrollIndicator = true;
    win.add(scrollView);

	for (i = 0; i < toppings.length; i++)
	{
		//-- The label
		var toppingLabel = Ti.UI.createLabel({
			text:toppings[i].title,
			font:{
				fontFamily:'Verdana',
				fontWeight:'bold',
				fontSize:14
			},
			color:'#fff',
			shadowColor:'#333',
			shadowOffset:{x:1,y:1},
			textAlign:'left',
			width:Ti.Platform.displayCaps.platformWidth - 10,
			left:10
		});
		
		//-- We add a custom property 'selected' to our checkbox view
		var checkbox = Ti.UI.createView({
			width:340,
			height:16,
			backgroundImage:'../images/checkbox_no.png',
			selected:false,
			toppingID:i
		});
		
		//-- if the user hits cancel in the details window, we go back and repopulate the list with previously checked toppings
		if (win.returnToppings)
		{
			for (j = 0; j < win.returnToppings.length; j++)
			{
				if (win.returnToppings[j] == toppings[i].title)
				{
					var aTopping = Ti.UI.createView({
						backgroundImage:toppings[i].path
					});
					
					if (Ti.Platform.osname == 'android')
					{
						aTopping.image = toppings[i].path;
					}
					else
					{
						aTopping.opacity = 0;
						aTopping.animate({
							opacity:1,
							duration:500
						});
					}
					toppingsHolder.add(aTopping);
					toppings[i].container = aTopping;
					checkbox.backgroundImage = '../images/checkbox_yes.png';
					checkbox.selected = true;
					numToppings += 1;
				}
			}
		}
		
		var toggler = Ti.UI.createView({
			width:Ti.Platform.displayCaps.platformWidth,
			height:20,
			top: i * 20
		});
		
		//-- We use the singletap event rather than the click since its in a scroll view
		checkbox.addEventListener('singletap',toppingListClick);
		toggler.add(toppingLabel);
		toggler.add(checkbox);
		
		scrollView.add(toggler);
	}
	scrollView.animate({
		opacity:1,
		duration:500
	});
}

Conclusion

In this tutorial we created the "Submit Oder" screen that is the last screen we will need in this tutorial series. We also added two more custom events to our app that allowed us to jump between the "Choose Crust" and "Submit Order" screens.

The next part of this series will go over doing the form authentication necessary to handle submissions and then e-mailing the order chosen along with the customer information submitted (a web server with a mail client and PHP installed will be required in order to send the e-mail order notification).

Advertisement