Tools • 1:06:22
Dashcode 2.0 includes a wide variety of tools to help both beginning and expert web developers quickly create great iPhone web applications. See how you can save time with an extensive drag-and-drop library of UI controls and JavaScript code snippets. Learn how to customize the new iPhone web application templates and understand runtime behavior using Dashcode's powerful JavaScript debugger. Discover a new way to create powerful, polished web applications for iPhone.
Speakers: Mike Ferris, Dan Gobera, Mike Kahl, Sarah Laiwala
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon, everybody. I'm Mike Ferris, and I'm really pleased to be here today. I hope that a lot of you saw the demo of Dashcode that was in the Developer Technologies State of the Union on Monday. And for those of you who did, I just wanted to say that, Dave, you know, if you're out there, I have faith that this is where you would have chosen to go this afternoon. Now, we introduced Dashcode in the Leopard release of the developer tools a while back, and it was a brand-new IDE for developing widgets, dashboard widgets.
Now, we actually, we love widgets. And in fact, there's a session on Friday where we're going to talk about all of the stuff that we've been doing for widget developers and about how to use Dashcode to develop widgets. But today, I'd like to focus on the new version of Dashcode, Dashcode 2.0, which is shipping with the iPhone SDK. In this version, we've actually taken advantage of the web technology foundation that Dashcode is built upon to add support for developing iPhone web applications. That's what I want to talk to you about here today.
We actually have a full session today. We're going to talk-- I'll give you a brief tour of Dashcode first. And then we're going to spend the rest of the session building a complete web application. We'll show you how to design the interface and structure your application. We'll show you how to interact with a web server to fetch your application's content. And then finally, we'll apply some finishing touches and polish before deploying the application for everyone to use.
The application that we're going to build today is Sugarwater. Imagine that you're at a party with a whole bunch of thirsty people, and somebody asks you to play bartender. Well, Sugarwater can help you. Tell it what ingredients you have available. It will suggest drinks that you can make and give you the recipes. We're going to build this application here today. But before we do that, let me go to the demo machine and actually give you a brief tour of Dashcode. Can I have the demo, please? Thank you.
So when you first launch Dashcode, you'll see the Template Chooser panel. This is where you can choose from a number of different starting points to make your application. And as you can see, all the widget templates are still here. But now there's a new category of templates for web applications.
The Custom Template gives you a blank slate to start from to build your application. The last two give you nearly complete web applications where all you really have to do is supply an RSS or a podcast URL. The browser we'll actually use for our application later. So for now, let's start with the Utility Template.
The focus in Dashcode is on the canvas. This is this large area in the center where your application's interface is shown. To the left is the Navigator. This is where you can see the DOM structure of your HTML. Below the Navigator, each template comes with a set of steps to help guide you through the things that you'll need to do in order to complete the application. And in that same area, you can display all the files that are part of your project. When you're ready to start editing your JavaScript, Dashcode's integrated code editor appears beneath the canvas. Dashcode also has an inspector panel.
Where you can view and edit properties associated with the current selected elements in the canvas. and a library where you can find parts and code snippets to add to your application. Let's see what happens when we run our application. When you run, Dashcode launches your web app in the iPhone simulator so that you can see exactly what it'll look like on the phone. Back in Dashcode, the canvas has been replaced by a run log where you can see any console output that your application generates for debugging purposes and where any errors are reported as well.
Now, if we stop, if we pause the application, then we start to get debugger controls. As you can see, the stack backtrace, along with all the local variables for where we've stopped, is displayed in the upper area. And down below in the code view, Dashcode highlights the line of code where you're currently executing. So we're going to see a lot more of all of these things later on. But for now, let's go back to the slides.
So we've just seen basically all the components of Dashcode's workflow. The main point to take away from this is that Dashcode is centered around visual interface design. The canvas is the centerpiece of the window, and you do all of your interface design in that area. You add user interface elements to your application by dragging parts out of the library. Parts are basically prepackaged interface elements. Once they're in there, you modify them through direct manipulation on the canvas or through the inspectors. And then finally, when you're ready to start adding behavior to your application, you use the integrated code editor.
Now, there's a lot of different ways to write a web application. Dashcode uses a pattern that's been gaining popularity in recent years called Ajax. Ajax applications have a couple of distinguishing characteristics. They tend to fetch their content asynchronously, and they manage their interfaces by modifying the DOM directly.
As a result, Ajax applications feel more responsive. And they can be more immediate because they don't rely on page loading to refresh their interfaces. They can also take advantage of advanced CSS and JavaScript functionality, like the CSS visual effects that have been described in other sessions during the week.
All right, now that we have an understanding of the basics, let's actually get started building our application. And to do that, to show us how to design the interface and how to structure the application, I'd like to ask Daniel Gobera to come up and give us a hand.
Thank you, Mike. Good afternoon. My name is Daniel Gobera, and I'm a software engineer in the Dashcode team. And what I want to show you today is how Dashcode can help you get amazing results in a very short time when designing your iPhone web application. We'll take a look at the visual tools for designing the application and at the library of parts. So let's start by looking at the recommended architecture for applications.
Mike mentioned that iPhone web applications tend to use AJAX to get the data from the server asynchronously, typically in XML or JSON format. Well, on the client side, the application is going to be structured using the model view controller pattern. Now, the model layer is the one that is responsible for managing all the data on the application, including the one that came from the server.
The View layer is going to present the interface to the user using HTML and CSS. The Controller layer is the JavaScript code that ties the other two together. One of the biggest benefits of this structure is that the code is going to be highly reusable. So, for example, you can use the same model objects in another application or simply replace the view layer to get a different user interface. Well, regardless of the architecture you choose for your application, I would really like to encourage you to do one thing.
and that is design before you build. Really, you will get dramatically better results if you just take some time before you start actually building the application to get a clear idea of what you want it to be. For example, for the Sugarwater application we're going to be building today, it will be an application for thirsty people to find recipes of mixed-use drinks. This is just one sentence that describes what the application is going to be. And notice we're identifying our target audience. So if you ever met a thirsty person, you know that they can be dangerous. And probably not as bad as hungry people.
But we better provide a very simple search and provide results really quickly because they want their drink right now. So all our design is going to be based on that. And the image you see here is not just a decoration for the slide. Well, probably the coffee stains. But this is actually the sketches we made for when we were designing the demo we're going to be building today. So you can get a clear idea of how the user is going to navigate between the multiple views and how the application is going to be structured.
Once you have the clear idea of what you want, it's time to launch Dashcode and start using the library of parts as the building blocks for the application. Mike mentioned some slides ago that parts are prepackaged interface elements. There's something I want to highlight here, prepackaged. This means that we have done all the work to write all the HTML, CSS, and JavaScript code to make these parts work correctly. So you don't have to do any of that. You can simply drag them from the library into your application, and they'll work. If you ever used Dashcode before, you may be familiar with some of these parts.
We have the buttons, shapes, controls, and fields. In Dashcode 2.0, we added some new shiny parts to support web application development. We have, for example, the list, which is a very common way to display information on the iPhone. We have the browser, which helps the user navigate to deeper and deeper levels of detail and then navigate back using the back button. Finally, we have the stack layout.
This one's interesting. It manages a set of swappable views where only one of them is visible at a time, and you can specify an animated transition between them. For example, the browser is going to use the stack layout to manage the multiple views, and it uses a push transition to go from one to the next. Let's look at the list and the browser in some more detail.
When you use a list, you're going to interact with the first row in the canvas. This is going to act as a template that will be cloned for every row of data you want to display. This means that whatever you put on that row is going to be replicated in the rest.
The way you put data into the list is by using the JavaScript API. If you've ever done anything in Cocoa, you may be familiar with the data source pattern. This is actually very simple. It's just a JavaScript object that you implement that responds to two methods. Number of rows and prepare row.
Number of rows is going to return the number of rows you want your list to have. So, for example, here we'll return four. Prepare row is going to be called four times so it has a chance to customize each of these rows and fill it in with data. It receives three parameters that I'll explain later in the demo. Let's look at the browser.
This one's going to help you show information in a hierarchical fashion so the user can navigate to different levels. And believe me, you don't want to write one of these from scratch. Let me repeat that. You don't want to write one of these from scratch. Really, just to get it to work in Keynote took me like an hour.
So to write it in JavaScript and CSS can be painful. So we provide it as a packaged part, so you can just drag it from the library and use it. It has a very simple JavaScript API used called the go-forward method. To make it navigate to the next view, you tell it to which view, and you tell it what is going to be the title in the other view.
So why don't we put all of these parts together and start building the Sugarwire application? This application has two views, one with a list of drinks and one with the detail of the drink the user selects. So probably the browser is going to be the best starting point for this.
This template already has a browser part, and as we saw before, the browser uses Stack Layout. The Stack Layout has two views in this case. It can have as many as you want. It has one for the list level and one for the detail level to display the detail of the item selected.
This is good because I do want a list, but I don't want this kind of list. So I'm going to remove it, and from the library of parts, I'm going to drag the other kind of list, which is the rounded rectangle. Now, it doesn't look very good on white, so I'm going to remove the background in the graphics vector. And those stripes, we have seen them over and over, so they're a bit boring for sugar water. Let's just change that background.
and Mike Krahl. The header doesn't match. Let me change the colors for that. While I'm doing this, Dashcode is generating all the images to get the glass and gradient effects and just putting them in the right place. So you never have to go to an image editor and bring the images back. Let's just change the title.
Okay. Now it's time to customize the list. In every row, I want to display the name of the drink, a description, an image, and the rating to show how good it is. So I'm going to make it a bit larger so I have some space for that. Notice that when I modify the template row, everything else is affected.
This is going to affect how every row is going to be displayed. I'm going to have an image here that will be just a placeholder to help me with layout. And to show the summary, I'm going to have another text part, which I'm going to drag from the library, put it right here.
Make it probably as wide as the other one. And let's make the font smaller here, maybe gray. Now, to display the rating, I could use some images, but Dashcode provides another part, horizontal level, which is going to be very useful for this purpose. If you don't like the gray bars, it's showing by default. That's not a problem because this part is totally customizable. So you can change the images. Let's just change it for an empty star. and a yellow star for the on state. Now, I want five stars here, so I'm going to make this a bit wider.
And I'm going to tell it to use a range from 0 to 5. And the initial value is going to be 3, so I can see how it's going to look like. Now, the important thing to know here is that while I'm doing all this, Dashcode is generating all the HTML and CSS code to get this effect. So, just to show you here.
I'm going to open the CSS file and navigate to the rule that applies to the arrow. And you can see that while I drag it around, it is regenerating this CSS file. And just look at that. I mean, it's gorgeous CSS. It's completely readable, and it's very well-structured.
So if you want, if you need to, you can go here and change it by hand. Most of the time, you won't need to. So let's just hide it. Now, to be able to filter this list, I'm going to have a set of buttons. Each button is going to represent one ingredient the user can turn on and off.
For that, I'm going to have a rounded box, which is going to be the container for the buttons. Let's make it a bit taller and maybe give it some transparency. Oh, sorry, something I forgot. We need to be able to find these elements during runtime. So I'm going to give them better names. This is going to be the drink name, the drink image. The drink summary and the drink rating.
Now, since I want a button for each ingredient, I'm going to drag the bottom part from the library, put it right here. And I'm going to resize that to be maybe 45 by 50. I don't want a label in this button, so I'm going to remove it. I instead want an image for each. So I can go to the Attributes Inspector and drag. This is going to be my pineapple button.
Now, Dashcode already generates a pressed version of the image, which is slightly darker. I want to use my own, so I'm going to use the one with the nice purple glow. Okay, so once I have that, well, it doesn't look very good with that background. So let's remove the fill and the stroke.
I want to have six of these buttons, one for each ingredient. So I can just press Command-D to duplicate. And Dashcode's going to show some guidelines to help me align them. And if I press Command-D again, it's going to remember what I did to the previous one and keep doing it until I have six I want. And just let's give them a name so I can know which ingredient they represent.
It's going to be the pineapple, and you probably don't want to see me change all of them. So as in any other good cooking show, we have something ready out of the oven. We simply changed the images for all the buttons and assigned IDs for the names of the ingredients. OK, so we are done with the layout. It's time to make this actually work.
This list is a static list. That means that here in the inspector, we say what data is going to be in each row. Let's make it dynamic so we can change it during runtime. As we saw, the list uses a data source. In this case, I'm going to use ListController.
This is a JavaScript object that came with a template, and it implements the two methods we saw, number of rows and prepareRow. I want my list controller to also keep track of the drinks being shown and the ingredients used for filtering. So what I'll do, I just add a bit of code here.
and the rest of the team. To add a drinks and ingredients properties, they're just simple arrays. They're initially empty. The set drinks method is going to reload the data on the list. Now, in Dashcode, when you want to call a JavaScript API of a part, you get a reference to the main element using getElementById, in this case, the list, which is this element right here.
And you use the dot object property to get access to all the methods. So in this case, we're calling reload data. To fetch drinks later on, we're going to retrieve the real data from the server. For now, just to get us up and running, we're going to use some sample data. which I'm going to drag right here. It's just a JavaScript array where each object represents the data of one drink.
Now it's time to implement number of rows and prepare row. Here I want to return... The number of elements in the drinks array. So I can do that. And if there's nothing in that array, I still want one row so I can display a message that says no results, right? Now in prepare row, we're going to customize each of these rows. So I'm going to remove the implementation that came with the template and add the one I wrote a bit earlier.
It's actually very simple. Remember it receives three parameters? Row element is the actual DOM element for the row we are preparing. Row index is the number of the row we are currently processing. and Template Elements, this one's interesting. Remember, all of these elements have an ID, but they're going to be cloned. Well, in the DOM, duplicate IDs are not allowed. So when they're duplicated, we need to remove the IDs.
How are we going to find these elements? Well, Template Elements contains a reference to all the elements in the current row. So let's see an example. Here, I'm getting the current drink to display from the drinks array. And through template elements, I am getting the drink name. This is the same ID that the original element had. And I'm sending the inner text to the name of the drink.
Then I'm doing the same with the source of the image to the summary, to the text of the summary, and setting the value on the rating. Notice that, again, we're using the dot object property to access the JavaScript API. Finally, I want to add a click handler to the row so when the user selects it, we can do something.
Here we are notifying the detail controller to fetch this drink. I'll explain this later. We're getting a reference to the browser. And again, through the dot object property, I'm calling the go forward method. I wanted to navigate to the other view, which is detail level. It is this one. And I want to set the title to recipe when we navigate to that view. If there are no results, I am setting the drink name to be no drinks and hiding all other elements.
One more thing we have to do. The detail controller is the controller element for this view. It's going to control everything that happens here. So let's remove the implementation that came with the template. And I'm going to have a really simple one. For now, I just have a fetch drink method. It gets a reference to detail title element, which is this one. And it just sets the inner text to the name of the drink.
And to get things up and running, when the application loads, it's going to call the load method. In here, I'm going to call this controller .fetchDrinks. So you can see something with the application launches. So I think we're ready to run it and see if things are working.
So it launches in the simulator, and we can see that the list is being filled with the data from the sample data array we had. and when I click on one of them, the browser navigates to the next view and shows the detail for this drink. Well, for now, it's just the title, but we'll change that later.
It also keeps track of the current title, the Back button, and it knows how to navigate back. Notice I never had to call another method to go back or to tell it how to go back. Now, these buttons are still not working, so let's do something about that.
I go back to the list level and I can just select all of them. And over here in the behavior inspector, I can assign a JavaScript function handler for any of these events. So when the user clicks, I want to call ingredient clicked. If the function does not exist, Dashcode is going to generate it for us, and we can simply fill in the contents.
So I'm going to have a simple implementation for that. This just gets an element-- sorry, gets a reference to the button that was clicked. And from the ID, I will know the name of the ingredient. I'm going to notify the list controller and tell it to toggle that ingredient for filtering. And based on the result of that, I'm going to set-- Set the state of the button to be on or off so it remains highlighted.
So I only need to implement this method in the list controller. So I'll just scroll back up and... This is just a very simple method that keeps track of the ingredients array, adds and removes ingredients, and logs in the console. Which ingredients we're using for filtering. For now, it's not going to actually do the filtering. It's just going to log in the console what's happening. I think we can run it again. It's really important to run the application very often, as often as you make changes to check that everything is working.
So if I test these buttons, I can see that they remain in the on state, and the console is logging the current ingredients I'm using for filtering. So that's good. This is working. And this is as far as we'll take it for now. We'll finish it later. So if we can go back to slides, please.
So what we saw in this section is how to use the model view controller pattern for iPhone web applications. And we saw how to use the visual design tools to design the interface visually without writing any code. And how to use the parts as the building blocks for the application. Well, once we have the interface up and running, it's time to make it really work with real data. And for that, I want to introduce Michael, who's going to help us retrieve some data from the server. So, Michael. Thank you.
Thanks, Daniel. I'm Mike Kahl. I work on Dashcode. And today I'm going to show you how we can hook up this web app to live data. We have set up a web server that maintains a database of drink recipes, and it responds to various queries. Let's take a look.
Here's a sample query that is a URL and it asks the server for a list of drinks made with certain ingredients. And the server might respond with a list of drinks and some summary information about each one. Here's another query. This one asks for the recipe for a given drink, and the server might respond with expanded information about that drink, including the recipe.
I'd like to talk a little bit about the format of these responses. We've chosen not to use some complicated XML that we would then have to parse. Instead, the server is supplying results that look just like the JavaScript data that our web app already knows how to deal with. This is known as JavaScript Object Notation, or JSON.
JSON is a data interchange format that is being used more and more these days as an alternative to XML. Its advantage is that it's very easy to read, both by humans and by computers. There are JSON implementations for dozens of programming languages. But its simplicity is particularly apparent with JavaScript because JSON is, in fact, a subset of the literal syntax that JavaScript already understands.
So parsing JSON can be as simple as just calling eval, which is a built-in JavaScript function that takes a string and executes it as JavaScript. And the parentheses are there to tell eval that its argument is an expression and not a statement. So is that really all there is to it? Well, yes and no.
If you totally trust the data coming down from your server, then yeah, it's fine. But eval will execute any JavaScript, not just the JSON subset. So a problem on the server could adversely affect your client as well. It might not be such a good idea to just blindly eval arbitrary JavaScript. We can get a little bit more sophisticated.
There are two things we can do. First, we can catch any exceptions, such as a syntax error, that might occur when we try to eval the string. And secondly, We can preflight the string to see whether it looks like it's safe to eval. If it's not safe to eval, or if there's a syntax error or other exception, then this parseJSON function will return undefined.
Let's take a look at our preflighting code. Now, this uses regular expressions. It's a little bit messy, but bear with me. It's actually not as bad as it looks. This comes from the JSON specification and it's based on a simple observation. Outside of constant strings, JSON actually has a very limited character set.
So we remove the strings and then we check to see whether what's left consists only of characters that can appear in valid JSON. And the important thing to note is that valid JSON cannot include parentheses. And without parentheses, you can't make a function call. And it can't contain an equal sign, so you can't do assignment. So although a string that passes this check isn't necessarily guaranteed to be valid JSON, at least it's pretty much impossible for evaling it to do any damage.
So let's return to how we get the data down from the server. These are our steps. We're going to use two technologies, JSON, which we've just talked about, and XML HTTP request, which is a JavaScript object originally designed to retrieve XML data from a web server, but it works just as well with any kind of data, including JSON.
So we're going to replace the implementation of this fetch drinks method of the list controller, which is called whenever we need to repopulate the list of drinks, and in particular it's called when the web app first is loaded. We'll start by creating a new XML HTTP request instance. And we'll point it at our web server by supplying an appropriate query URL. Also, we disable caching so that we always get the most recent drink recipes from our constantly changing database.
And an important thing to know about XML HTTP request is that it's asynchronous. When we send this request, the reply is going to come back sometime later, hopefully only a few milliseconds later. But still, we need to treat the arrival of the data as an asynchronous event by specifying a callback function which will be invoked when the event occurs.
Finally, we send our request out into the world. And we also record a reference to the request that we sent most recently. And we'll see in just a bit why that turns out to be a useful thing to do. But first, let's look at how we construct the query URL.
If no ingredients are selected, then we ask the server for a list of the most highly rated drinks. If one or more ingredients are selected, then we ask for the drinks that are made with those ingredients. And it's generally a good idea to call encodeUri, which is a built-in JavaScript function, in order to percent encode any special characters that might appear in the ingredient names.
So that's our query. Now let's move on to the function that is called to process the data once it arrives. Now, remember, the data arrives asynchronously. So we need to think about what would happen if while we're waiting for the data to arrive, the user selects another ingredient. Well, fetch drinks will be called again, and a second request will be issued, and now there'll be two requests outstanding. And both responses will come back, and they might even come back out of sequence, because the Internet is unpredictable that way.
We need to defend against that. So in the receive data method, we make sure that we act only in response to the request that we sent most recently. If a response arrives, if a response to an earlier request arrives later out of sequence, then we want to ignore it.
Okay. If everything went well, we now have a list of drinks in JSON format. But if there was a server error or if the JSON was ill-formed in any way, then this drinks variable is now undefined. Finally, we can update our UI. Now, in your own web apps, you might consider having more robust error reporting than this. But this is a demo, so if anything went wrong, we will fall back on an empty list for the list of drinks. Okay, let's try it out.
So this project is pretty much as Daniel left it, except that I've removed the dummy sample data. We won't be using it anymore. And I've added in all the code that we just saw from the slides. So let's give it a try. How many people think that this is going to just work the first time? If it works the first time, then I won't get to show you Dashcode's debugger.
through an exception. Let's take a look. Dashcode is telling us See that? Dashcode is telling us that this.receiveData was undefined. So let's look at the code. We're trying to call the receiveData method of the list controller. Well, let's go to the variables view and take a look at the this object.
And that doesn't look like our list controller at all. In fact, that's an XML HTTP request. How did that happen? It turns out that in JavaScript, whenever a function is called, The this object always receives a fresh value. You can think of it as a hidden argument to the function.
In this case, when the callback function was called, the system, for whatever reason, passed in the XMLHTML request object. Well, we wrote this code expecting that we could refer to the list controller from the outer scope. Well, that's a common programming error in JavaScript, but it's easy to work around.
We just introduced a new local variable, and we'll call it self because we're Objective-C programmers, and self is not a reserved word in JavaScript. And we'll make it refer to the list controller. And then we change our method call to use that instead. So let's run it. How many people think it's going to work this time? Still no bites.
Well, this time, no exception, but also no drinks. So to debug this, we're going to use a new feature of Dashcode 2.0, the resource log. The resource log is a list of the resources that have been loaded at runtime, whether from the local file system or over the network. We're interested in seeing what came in over the network. and nothing came in over the network. That can't be good. What happened to our query? Here it is. But look at that URL.
We thought that query was going to go to our web server, but it tried to find it on a local file system, and of course there was no response. So let's go look at the code that constructed that query URL. And it's true. We never explicitly named the web server.
We just assumed that The query would go to the same server that the web page came from. And that's actually a valid assumption once we've deployed this web app and we're viewing it on our iPhones. But during development, the web page, the HTML, comes from the local file system. But the query still needs to go to the server.
So to work around that, we're going to introduce a base URL, which is going to be a global variable that will initialize to point explicitly to our web server only when we're running under Dashcode. When we're deployed, we want it to be the empty string. So in order to figure out how to make that distinction, let's turn to JavaScript's evaluator, which is a JavaScript console and our web app is still running, so we have live access to the JavaScript world.
There's a property, location.href, that tells us where the HTML file came from. And as you can see, it's a file-based URL. Now, I think there's another property that might be more useful. We can find it using code completion. That's the one I was thinking of, and that's just the file colon portion of the URL. So let's use that.
Go down to our onload handler and initialize base URL depending on location.protocol. If it's file colon, then we'll name our web server. and otherwise, we want it to be the empty string. Okay. Now, there's actually one more place where we need to also refer to base URL because we're loading images from the server. Okay, now we're ready to run. Third time's a charm, right? And this time everything works. We've got our list of popular drinks.
We've got our list of popular drinks, and let's look at the resource log. Here's our query. This time it went... To the web server, there was a response. And we can even look at the JSON that came back. We can also see the images that were downloaded from the server.
Let's try out our filtering. Here are the drinks that are made with orange juice. Here are the drinks that are made with orange juice and honey. Oh, there's only one. I want to point out, it looks like in our drink summary that there might be some words missing. Can you see that? So let's go look at the resource log again.
And yeah, it's true. It looks like the words "plenty of fruit" got clipped. What we'd like to have happen is for the list row to get taller automatically in order to accommodate any extra text. Well, we're going to show you how to do that a little bit later in the session. But first, there's one more thing I want to do. I want to implement the last query, the recipe query. This is the query that's going to be made whenever we select a drink and go to the detail page.
So let's go to the detail controller. And I'm actually going to replace the detail controller with some code that I have up my sleeve here. This code should be very familiar. We fire off an XML HTTP request. Here's our query. It's a little bit different. This time we're asking for the recipe. The data comes in. It's JSON. We display the UI. It's very much the same code as we saw before, just this time in the detail controller instead of the list controller. So let's run it.
And now when we click on a drink, well, we don't actually see any visible difference because we haven't hooked up the UI for the detail page yet. But the data's there. Well, we're going to be hooking up that UI a little bit later in the session, but it would be a good idea to verify that the data did arrive correctly. Now, we could use the resource log again, but Let me show you a different way to do it. I've already shown you that a couple times.
We can go and we can set a breakpoint here in the code at the spot where we're about to display the drink data. And now, when we click on a drink, the breakpoint is reached. And we can go up to the variables view and twist down the drink variable and see that all of the fields have been properly populated. So it works. Back to slides, please.
Okay, so we've seen how to hook up a web app to a web server and get the data down. And we've gotten a quick tour of Dashcode's debugging facilities. And we've gotten a few hopefully useful JavaScript programming tips. So now, to put the finishing touches on our fledgling web app, I'd like to introduce Sarah Laiwal. Sarah? and I am proud to be a Dashcode engineer. I'm going to show you how to add finishing touches to your iPhone web application.
First, I'll cover a few advanced positioning and layout techniques so that we can ensure your web application is polished and can adapt to a changing environment. Then I'll show you how to add a home screen icon to your web application using Dashcode and then share your web application with the world.
provides you with two ways to lay out the elements in your interface. The first one is absolute positioning, and the second one is document flow positioning. Appset positioning is useful when you don't expect elements on your page to grow or interact with one another. You expect them to remain independent of each other and in the same location relative to their container.
AFSA positioning is also advantageous when you want to achieve complex designs, like overlapping elements. But although absolute positioning has its benefits, it's not always advantageous when you have a layout like this. You have two boxes that you're designing at design time, but you don't know how much text you're receiving at runtime.
So if you receive one sentence from the database, that's great because this layout works. But if you receive multiple sentences, then the green and the blue box start to overlap and the text becomes unreadable. So what you'll want to do here is change the positioning from absolute for both the boxes to document flow. So as the green box expands, the blue box gets pushed down. Now let's look at another situation where the elements on your page can be affected.
The iPhone can be held in portrait mode or in landscape mode. And you want the elements on your page to be able to interact with this. So Dashcode provides you with the layout tools to do just that. If you've used Interface Builder before, the concept of springs will be very familiar to you. And if you haven't, well, that's OK.
Just playing with Dashcode for a couple of minutes will make things clear. So suppose you have an element that you want centered when the iPhone orientation changes. What you'll do here is set springs on the outer horizontal margins to make sure that the box's width is constant. So as the iPhone rotates, your box remains centered.
Let's suppose you want the elements on your page to grow as the iPhone orientation changes. What you'll do here is set inner horizontal springs to make sure that the box's width is now variable. As your iPhone rotates, your element grows. You might want a pinned behavior where you want certain elements to stay pinned in certain locations, like to the left or to the right. By setting the appropriate springs, you can accomplish that.
So now that I've shown you how to layout, how to add finishing touches to your layout, I'm going to show you how to add a home screen icon to your web application. Now you might be wondering why you should do that. Well, you should do that because the iPhone has several icons.
It has a mail icon, the stocks icon, lots of icons. And Safari allows you as a user to add a home screen icon for your web application to the home screen. So you want an icon that represents your web application when the user adds your web application to their home screen.
The Dashcode has a design editor that lets you do that. We give you the proper iPhone dimensions. And via the inspector, you can add a gradient or color to the background. And if you have an orange or an image, you can pop it right on. So now that I've shown you how to lay out the elements on your page or add finishing touches to them, and I've shown you how to add a home screen icon to your web application, I think you're ready to share your web application with the world. So Dash Code lets you deploy to three types of web servers.
You have .mac, webdev-to-mac-os10 server, and local web server. If you choose not to deploy to one of these servers, that's all right, because Dash Code lets you save your website folder locally, and then you can deploy it to wherever you want to deploy it to. So let's go ahead and add these finishing touches to Sugarwater.
Earlier, the iPhone has two different types of orientation: portrait and Landscape. Sugarwater is currently in portrait mode. If you'd like to see it in landscape mode, You can click on this button right here that says "Rotate to landscape orientation." And by default, Dashcode scales a page up to fit the wider screen.
If you don't want the page to scale up to fit the wider screen, you can go into Application Attributes. and select Adjust Page Width to Fit so that when you rotate Sugarwater again, now the page has grown wider to fit the wider screen. For Sugarwater, we're going to keep this setting.
And if we keep the setting, notice we have too much white space over here, and the button box is no longer centered. So this doesn't look good. So we'll go ahead and select the button box. Open up the inspector. We'll go into the metrics inspector and put outer horizontal springs on the margins. So as the iPhone rotates, the button box remains centered.
Now, if you recall from Mike's demo, the text of the drink was being clipped off. And that was because the elements inside a list row are using absolute positioning, even though the list itself uses document flow. So our first instinct might be to make the text
[Transcript missing]
So, you'll want to do here is select Text and Ratings and change the layout to use Document Flow. So now, as the text expands, the ratings gets pushed down. But now we have another problem, and that's that the ratings, the list itself is not expanding. So we can select the list. and give it inner vertical springs so that the list's height is now variable.
As the text expands, the list begins to grow. This is exactly what we want. But now we have two more issues here, aesthetic issues. The first one is that the ratings is touching the bottom of the list row. And the drink and the chevron images are no longer centered. So let's solve both these problems. For the ratings, we'll just give it a bottom margin of 8 pixels. And we'll select the drink and the chevron and give them outer vertical springs.
So now, as the list expands, the drink image stays centered and the ratings have a bottom margin of 8 pixels. So now we're done adding finishing touches to the detail view. So let's-- to the list view. Let's proceed to the detail view. For the detail view, I've already added a box and image and done all the layout for that because you've already seen it being done in the two demos beforehand. So the crux of this page is that I want to be able to see the steps and the ingredients for this page, for the drink.
What I can do is drag a text box and make sure that the ingredients are always on top and the steps are always on the bottom. But if I do that, then my user is going to scroll a lot to find out that they might have to bake something at 350 degrees at the end. So instead of doing that, I want to use a stack layout, because the stack layout provides me with two views.
So I can easily use that and go from the ingredients view to the steps view. So I'll go ahead and drag a Stack Layout. And again, Stack Layout has two views, view one and view two. And in view one, I want to show the ingredients. So I'll drag in a rounded box and a text part.
The text is touching the left wall, and that doesn't look good. So we'll go ahead and give the box a text padding of... That looks better. And because we want to go from the ingredients view to the steps view, I need a push button, which I'll put directly under the text. And now let's make the button look like the back button by giving it a color using the sampler.
And now let's go ahead and take a look at how this page responds to the iPhone orientation change. Notice that the button is no longer to the right of the box. To fix that, we need to give it springs. And we will give it left springs. So now as the iPhone orientation changes, the button itself remains to the right. So this is good. And we'll expand the text just a little bit.
This is the Ingredients view. The Steps view looks exactly like the Ingredients view, except it's going to show the steps. So I'm just going to copy this box and paste it into View 2. Now, before I write any code, it's always best practice to rename these IDs. But because you've already seen IDs being renamed, and it's kind of a boring thing to look at, I'm going to-- Open up this project right here, which is everything that you've already seen, but the IDs are renamed. And now, let's go ahead and take a look at how our interface looks.
You can go ahead and select the orange and the honey. And now we'll see that sweet and creamy with plenty of fruit is now showing. The entire text is showing for this drink. And here's our steps view. And nothing happens. And that's because I haven't set the onClick handlers for this button. So we can quit out of the simulator. And we'll go here and select ingredients, go into on click, and say show ingredients right here.
For those of you who don't want to show you how to type all this code out, I already have snippets ready for you. And I'm going to drag show ingredients and steps. I'm going to remove this. discuss this code. So show the ingredients. All it's doing is getting The Detail Stack is getting the Stack Layout by its ID called Detail Stack and then setting the current view from the Stack Layout API to show the ingredients view.
StepsView is doing the same thing. Show Steps is doing the same thing, except it's taking us to the StepsView. So for the Ingredients button, we'll add the on-click handle, which is Show Ingredients. I already did that, so it's there. And for the Steps button, we'll go ahead and say Show Steps. will test the transition from Steps view to the Ingredients view and the Ingredients feedback to the Steps view.
Again, I'll select orange and honey. Look at steps and it goes to ingredients and ingredients goes back to steps. But because we've already used this push transition to go from the list view to the detailed view, we should probably use another transition to go from the steps to the ingredients view back to the steps view. And of course, the back end is not connected to the front end, so we should take care of that.
To change the transitions, we'll select the stack layout, go into the inspector, and change the transition from push to flip. And now we'll connect the back end. What the back end is doing is getting the reference to an object, and setting the text to be its inner HTML. So we'll hit Run.
will stick to the honey and the orange drink. And now we can build our drink with these ingredients. uses the flips to the ingredients and ingredients back to steps. So this is working. And we've finally finished polishing sugar water. So our next step is to add a home screen icon. To do that, I'm just going to go into the Fill and Stroke Inspector.
[Transcript missing]
So, like Steve has his one more thing, I have my own one more thing, and that's Dashcode will send an email to you with a deployed web application, a link to the deployed web application, so that you can easily test your web application on the iPhone. So, I'll just select that and hit Deploy.
We'll go to the iPhone. Unlock the phone. And now we have a message waiting in mail. It's from dashcode team dot mac. And there's a link to Sugar Water. So we'll go ahead and hit that. And wait for Safari to load the page. and we have our drinks on the iPhone.
So let's go ahead and make sure... So let's go ahead and make sure that our button box is centered as the iPhone orientation changes from portrait mode to landscape mode. Of course, this has sticky on the back. And I turned it off. Your button box is centered. I'll lift it again. Time. I no longer want that orange honey drink. I want a coffee ice cream drink.
and I have a cappuccino cooler. And we can see here what the ingredients are to make the drink. and I'll start to make the drink. And our flip transition is working nicely as well. So now let's go ahead and take a look at our home screen icon. So using Safari, we'll add this web app to our home screen. There's Sugarwater, and there's my pretty icon. Hit Add. And I'll never be thirsty again.
We've got a lot of information today, a lot. And what I hope you take away from all of this are The following things. Dashcode is now for widgets and web applications. We let you create Ajax-based applications visually with our prepackaged parts that already have behaviors associated with them. We have layout tools available to you so that you can make sure your web application is polished, can adapt to a changing environment, and can adapt to dynamic content.
We also have a built-in debugger and runtime tools for you to solve your coding issues. And when you're ready and comfortable with your web application, add a home screen icon to it in literally seconds using Dashcode, and then share your web application with the world. We hope that what you've seen here today makes you excited to go out and use Dashcode as your web application IDE.
If you're more interested in Dashcode and related sessions, we have a few available for you. Unfortunately, Session 313 and 379 have already passed, but we'll have that available to you via iTunes after the conference. If you'd like to build your iPhone web application hands-on, come to the session on Thursday, tomorrow at 9:00 a.m. If you want to learn more about Dashcodes, primarily creating widgets, we have a session for you Friday at 10:30 AM.
If you have questions that we can't answer in today's Q&A, or you'd like to bring your code by so we can take a look at it, we have labs available for you on both Thursday and Friday. If you have more questions about labs, Dashcode, sessions, please contact Vicki Murley or Mike Jurwitz or our Dashcode User Guide.