## Week 9 Wednesday Andrew Sellergren ### Announcements and Demos (0:00-2:00, 73:00-75:00) + If you haven't already, check out the [Unofficial Guide to CS at Harvard](http://guide.cs50.net). + The Final Project Proposal is due soon. It offers three milestones which allow you to chart your progress toward a solid result. + The CS50 Hackathon is coming up in a few weeks! We'll offer a lottery for you to be able to join. If you're selected, we'll shuttle you to Kendall Square to Microsoft's NERD Center where you'll have a chance to spend all night coding your Final Project. Along the way, we'll provide you with plenty of food, soda, and camaraderie. ### Design (2:00-30:00) + Design flaws are all around us. Some hotel rooms have sinks with left and right knobs for hot and cold, but showers with left and right knobs for water pressure and temperature. This is arguably a flaw because the user's expectations don't match up with reality. + Design is not purely about aesthetics, or how things look. It's very easy to have error messages that look very pretty, but don't provide any useful information. This is not ideal. + Design tells us *what* we should build. Engineering involves *actually* building it. + One aspect of design is accessibility. If you're designing for deployment in a third-world country, you need to think about whether electricity will be available. If you're designing a web application, you need to think about users with disabilities. + Another aspect of design is cost. You may base your design decisions in part on the costs of different options. + More importantly, though, your design should be user-centered. You should ask yourself, "What are my user's goals?" Your job as designer is to help the user complete their goal in a manner that is: + efficient + intuitive + accessible. + If your application is efficient, it won't take the user a lot of time or clicks to accomplish his goal. If your application is intuitive, it's easy for the user to figure out what they have to click in order to accomplish his goal. If your application is accessible, users can understand its content no matter who they are. + Let's talk about bad design. When you navigate to Craigslist's homepage, your presented with links for all the different location-specific sites. Chances are only one of those location-specific sites is the one you want, but you have to wade through the rest in order to find it. Pretty overwhelming. + When you see the snippets for listings, you may notice tags that say "img" and "pic." What's the difference between these two tags? Nothing, actually. They mean the same thing. This is undoubtedly confusing for ths user. + When you click on a filter on Craigslist's search, you have to click the Search button to actually apply it. It might make sense to have the filter apply automatically when the user clicks it. This is possible using a technology called Ajax which Tommy will talk about shortly. + How could we improve Craiglist's homepage? For starters, we might want to add a blurb explaining what exactly Craigslist is. Instead of having the user scroll down to choose his location, we could provide him with a search box to search for it. + Let's talk about good design. When Facebook Photos came out, there were a number of other competing services. What set Facebook Photos apart was the tagging feature. This feature allowed photos to become a more social experience. + Let's talk about Facebook more generally, both good and bad. Maybe you find that the News Feed includes a lot of stories that you don't care about. Recently, Facebook has tried to improve this but boosting relevant stories to the top. Timeline allows you to find events in a person's history more easily, but it also has privacy implications. So too does Facebook Photos raise some privacy concerns. It's not always easy to know who can see your photos at any given time. Thankfully, Facebook has made efforts to make this easier and more intuitive. + How do you make design decisions when you disagree with your users? Henry Ford is often credited (perhaps apocryphally) with saying, "If I had asked people what they wanted, they would have said faster horses." Perhaps what Ford was trying to convey was that when you think about design, you should think about how you can fulfill your users' wants and needs, not necessarily exactly as they asked, but maybe in an even better, more impressive way that they didn't know was possible. + What produces the best results is a process of designing, testing, and iterating. You may think that what you've produced initially is the pinnacle of design, but your users may not love it like you do. If that's the case, you may need to take the aspects they do love and throw away the rest, iterating to the next version of your design. + Let's talk about Kayak. One of its nice features is the flexibility of its queries. You don't have to pick fixed start and end dates, for example. Another nice feature is that search results are updated instantly when you toggle filters. This is done using Ajax. The filters themselves are also very usable. Knowing only what you know now about HTML, you might resort to implementing a date picker with something like a dropdown menu. However, as Kayak demonstrates, there are other UI elements like sliders and calendar pop-ups that may make date picking more intuitive for users. This is what we mean by fulfilling your users' wants and needs in a way that they didn't know was possible. + As you implement your Final Project and other user-facing applications, you should keep in mind these [Ten Usability Heuristics](http://www.useit.com/papers/heuristic/heuristic_list.html). To get started, you can sketch out what you want your application to look like using pencil and paper. We call this process *paper prototyping*. For testing purposes, you can get a few people together in focus groups to play around with your paper prototypes and see if they really understand how to use it. After you have a design your happy with, do it all over again! It's important to design, test, iterate and then repeat. ### JavaScript (30:00-73:00) + Don't allow yourself to be overwhelmed by the complexity of applications like Kayak and Facebook. If you want to implement something like a slider for picking times, you just need to break it down into a few smaller problems. If you can detect when he's holding down the left mouse button using JavaScript, then you know when he is dragging. If you can detect where the user's cursor is using JavaScript, then you know how far he has dragged the slider. The rest is just a matter of combining some conditions. + Tommy is of the opinion that JavaScript is the best programming language there is. [Others](https://www.destroyallsoftware.com/talks/wat) might disagree. JavaScript's power comes from its ability to manipulate things that are already on the page. + When we access a webpage, it will be downloaded to our browser as HTML, which can be organized into a hierarchical tree known as the DOM. Much like a database can be queried using SQL, the DOM can be queried using JavaScript selectors. Here are some examples of JavaScript selectors: + `#submit` + `.centered` + `form input[type=text]` + The first selector in the list above will get us the HTML element with `id` of `submit`. The second selector above will get us all HTML elements that have the `class` attribute of "centered." The third selector above will get us the `` elements within a `
` element which have `type` of "text." + Ajax stands for Asynchronous JavaScript and XML. It allows us to make HTTP requests programmatically within JavaScript code. We can apply this to CS50 Finance so that users won't have to click the Back button and resubmit a form every time they want to fetch a stock price. In `quote1.js`, we have JavaScript code that will fetch the stock price for us asynchronously: $(document).ready(function() { // load data via ajax when form is submitted $('#form-quote').on('submit', function() { // determine symbol var symbol = $('#form-quote input[name=symbol]').val(); // send request to quote.php $.ajax({ url: 'quote.php', type: 'POST', data: { symbol: symbol }, success: function(response) { $('#price').text(response); } }); // since we're overridding form submission, make sure it doesn't submit return false; }); }); + Wrapped around all of this code is a call to the `ready` method of the jQuery-enhanced `document` object. The `ready` method takes as input a function that should be called when the webpage has finished loading. We pass to this method an anonymous function. This anonymous function attaches an event handler to the `onsubmit` event of the form, which we retrieve from the DOM using its `id` of `form-quote`. When the form is submitted, our innermost anonymous function will be called. This function first gets the value of the `` element which has `name` of "symbol." Then it passes this value, which should be the stock symbol, to the `ajax` method of the jQuery object `$`. To the `ajax` method, we pass an object which describes the HTTP request we want to make. In this case, the HTTP request is to URL `quote.php` using the POST method. In this HTTP request, we pass a single parameter named `symbol` containing the stock symbol we want to look up. The last property (named `success`) of the object we pass to the `ajax` method is a function we want to be called when the Ajax request is successful. This function takes a single argument named `response` containing the actual HTTP response from the server. We expect this HTTP response to be the price of the stock, so we're going to insert that into the HTML element with `id` of `price`. + It's important that we return false in our event handler function to prevent the original event (`onsubmit`) from actually firing. Since we're sending the form data programmatically in JavaScript, we don't want the form to actually submit or else the browser will navigate to the URL specified in the `action` attribute. + If we open up this webpage in our browser along with the Network tab in Chrome Developer Tools, we can see that an HTTP request is indeed issued when the "Get Quote" button is clicked. However, the URL of the page doesn't change at all. Eventually, the stock price is dynamically inserted into the page. + This is still a little annoying though since we have to click the "Get Quote" button each time we want to look up a stock price. What if instead we automatically fetch stock prices as soon as the user begins typing, just like Google Instant does for searches? To do this, we need only make a few changes: $(document).ready(function() { // load data via ajax when form is submitted $('#form-quote input[name=symbol]').on('keyup', function() { // determine symbol var symbol = $('#form-quote input[name=symbol]').val(); // send request to quote.php $.ajax({ url: 'quote.php', type: 'POST', data: { symbol: symbol }, success: function(response) { $('#price').text(response); } }); }); }); + Here, we're issuing Ajax requests after each `onkeyup` event in the text input box. The only other change we made was to get rid of the `return false` line. This time, we do want the `onkeyup` event to fire when we're done issuing the Ajax request simply so that the user's input actually shows up in the search box. + We can take this UI design one step further by implementing autocomplete. With autocomplete, the user will get suggestions for stock symbols as he types. We can implement this using the typeahead feature of the Bootstrap JavaScript library: $(document).ready(function() { // create autocomplete from list of stock symbols $('#form-quote input[name=symbol]').typeahead({ source: SYMBOLS }); // load data via ajax when form is submitted $('#form-quote').on('submit', function() { // determine symbol var symbol = $('#form-quote input[name=symbol]').val(); // send request to quote.php $.ajax({ url: 'quote.php', type: 'POST', data: { symbol: symbol }, success: function(response) { $('#price').text(response); } }); // since we're overridding form submission, make sure it doesn't submit return false; }); }); + To use this feature from the Bootstrap library, we need only call the `typeahead` method. We provide it with an array of stock symbols named `SYMBOLS` from which it can choose. + With a single additional function call, we were able to implement autocomplete. You'll find this is often the case, especially with frontend development. Always do your homework and find out if someone has implemented some feature already before trying to implement it yourself. + When might it be a bad idea to use autocomplete? If there are a lot of possible completions, using autocomplete might introduce a lot of latency. Also, autocomplete does not necessarily provide the most relevant completions first. + To add relevance to our suggestions, we're going to punt the hard work to Yahoo! Finance. We've written another file named `suggest.php` which will issue a query to Yahoo! to get stock symbol suggestions. Now, in our JavaScript, we're going to make an Ajax request to this file: $(document).ready(function() { // create autocomplete $('#form-quote input[name=symbol]').typeahead({ // load autocomplete data from suggest.php source: function(query, callback) { $.ajax({ url: 'suggest.php', type: 'POST', dataType: 'json', data: { symbol: query }, success: function(response) { callback(response.symbols); } }); } }); // load data via ajax when form is submitted $('#form-quote').on('submit', function() { // determine symbol var symbol = $('#form-quote input[name=symbol]').val(); // send request to quote.php $.ajax({ url: 'quote.php', type: 'POST', data: { symbol: symbol }, success: function(response) { $('#price').text(response); } }); // since we're overridding form submission, make sure it doesn't submit return false; }); }); + Before, the value of the `source` property of the object we passed to the `typeahead` method was an array of strings. Now, the value of the `source` property is a function which issues an Ajax request to get the stock symbol suggestions. The options we pass to the `ajax` method include a `dataType` property which is set to "json." JSON stands for JavaScript Object Notation, a way of specifying JavaScript objects in string format. Since we've specified JSON as the `dataType`, jQuery will return the HTTP response to us as a JavaScript object that looks something like this: {"symbols": ["AA", "AAPL", "AAP"]} + Let's try to implement the functionality of typeahead ourselves: $(document).ready(function() { // create autocomplete $('#form-quote input[name=symbol]').on('keyup', function() { // load autocomplete data from suggest.php $.ajax({ url: 'suggest.php', type: 'POST', dataType: 'json', data: { symbol: $(this).val() }, success: function(response) { // build html string for a list of suggestions var suggestions = ''; $('#suggestions').html(suggestions); } }); }); // set value of symbol field when a suggestion is clicked $('#suggestions').on('click', '.suggestion', function() { $('#form-quote input[name=symbol]').val($(this).text()); }); // load data via ajax when form is submitted $('#form-quote').on('submit', function() { // determine symbol var symbol = $('#form-quote input[name=symbol]').val(); // send request to quote.php $.ajax({ url: 'quote.php', type: 'POST', data: { symbol: symbol }, success: function(response) { $('#price').text(response); } }); // since we're overridding form submission, make sure it doesn't submit return false; }); }); + Since we don't have the `typeahead` method, we need to build our own HTML to represent the list of suggested stock symbols. We do this by iterating over the symbols passed back by `suggest.php` and constructing a string of HTML representing a `