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 += '• Plain (cheese pizza)\n'; } else { for (var i = 0; i < win.toppings.length; i++) { text += '• ' + 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:
![](/uploads/posts/9334/assets/legacy/Titanium-Mobile_Pizza-Place-App/three/step3.jpg)
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).
Comments