1 00:00:00,000 --> 00:00:02,958 [MUSIC PLAYING] 2 00:00:02,958 --> 00:00:16,480 3 00:00:16,480 --> 00:00:18,730 BRIAN YU: OK, welcome back everyone to web programming 4 00:00:18,730 --> 00:00:20,080 with Python and JavaScript. 5 00:00:20,080 --> 00:00:22,400 And so we'll pick off where we left off two weeks ago. 6 00:00:22,400 --> 00:00:26,276 So we've been working with building web applications in Flask using Python. 7 00:00:26,276 --> 00:00:28,150 And then last time, we introduced JavaScript, 8 00:00:28,150 --> 00:00:31,450 which was a language that was able to run inside of our web browsers, which 9 00:00:31,450 --> 00:00:33,844 allowed us to run some code on the client side, 10 00:00:33,844 --> 00:00:36,760 as opposed to running everything on the server, which allowed us to do 11 00:00:36,760 --> 00:00:39,867 things a little more dynamically, create more interactive user interfaces. 12 00:00:39,867 --> 00:00:41,950 And today, we'll continue to build on those ideas, 13 00:00:41,950 --> 00:00:44,140 continuing to work with Python and JavaScript, 14 00:00:44,140 --> 00:00:47,410 in particular, to take a look at some modern trends in web application 15 00:00:47,410 --> 00:00:50,530 development, and how we can use Python and JavaScript to be 16 00:00:50,530 --> 00:00:54,410 able to achieve those goals as we go about building our web applications. 17 00:00:54,410 --> 00:00:56,860 So the first thing that we're going to take a look at 18 00:00:56,860 --> 00:00:59,950 is single-page applications or single-page apps, 19 00:00:59,950 --> 00:01:03,536 which are becoming increasingly popular nowadays, where so far in the projects 20 00:01:03,536 --> 00:01:06,160 that we've built, we've been building a lot of web applications 21 00:01:06,160 --> 00:01:07,510 that have multiple pages. 22 00:01:07,510 --> 00:01:10,054 In the first project, you were building an application 23 00:01:10,054 --> 00:01:12,220 that dealt with interacting with a library of books, 24 00:01:12,220 --> 00:01:15,160 where you had one page where you might search for different books. 25 00:01:15,160 --> 00:01:18,460 And you get another page where you might look at individual details for a book 26 00:01:18,460 --> 00:01:19,690 and write reviews for that. 27 00:01:19,690 --> 00:01:21,170 And in the current project you're working on, 28 00:01:21,170 --> 00:01:22,660 you may building out multiple pages, where 29 00:01:22,660 --> 00:01:24,782 you have one page where people type in their name, 30 00:01:24,782 --> 00:01:26,740 for instance, and another page where people are 31 00:01:26,740 --> 00:01:28,570 looking at messages in a given channel. 32 00:01:28,570 --> 00:01:32,650 And what single-page apps are all about is taking content that would ordinarily 33 00:01:32,650 --> 00:01:35,890 be on multiple pages or multiple different Flask routes, 34 00:01:35,890 --> 00:01:37,660 you might think of them and combining them 35 00:01:37,660 --> 00:01:41,620 into just a single page, where that page will pull in new information 36 00:01:41,620 --> 00:01:44,410 from the server whenever it needs additional information in order 37 00:01:44,410 --> 00:01:45,970 to render in the browser. 38 00:01:45,970 --> 00:01:48,670 And so last time, we took a look at a technology 39 00:01:48,670 --> 00:01:52,000 called AJAX, which allowed us to asynchronously ask 40 00:01:52,000 --> 00:01:54,995 the server for more information whenever we wanted to include 41 00:01:54,995 --> 00:01:56,620 additional information on our web page. 42 00:01:56,620 --> 00:01:58,480 And we took a look at a currency converter, 43 00:01:58,480 --> 00:02:01,390 for example, where we could type in a currency 44 00:02:01,390 --> 00:02:03,880 and then retrieve information about the conversion 45 00:02:03,880 --> 00:02:07,540 rate of that currency from the server and then display that information 46 00:02:07,540 --> 00:02:08,830 right inside the web browser. 47 00:02:08,830 --> 00:02:10,090 And so we're going to take the same approach 48 00:02:10,090 --> 00:02:12,340 as we start to build single-page applications 49 00:02:12,340 --> 00:02:14,860 and looking at how we can start to build those out. 50 00:02:14,860 --> 00:02:19,210 So we'll start by taking a look at an example of an application that 51 00:02:19,210 --> 00:02:23,450 is not a single-page application or a multi-page application, so to speak. 52 00:02:23,450 --> 00:02:28,510 And so we'll take a look at this multi-page application, 53 00:02:28,510 --> 00:02:30,670 which is just going to be a Flask application that 54 00:02:30,670 --> 00:02:32,680 has three different pages. 55 00:02:32,680 --> 00:02:35,014 And so this looks very similar to the Flask applications 56 00:02:35,014 --> 00:02:36,221 that we've been dealing with. 57 00:02:36,221 --> 00:02:37,750 This one happens to be very simple. 58 00:02:37,750 --> 00:02:39,850 It's a Flask application with three routes. 59 00:02:39,850 --> 00:02:41,800 The default route, which is just slash, is 60 00:02:41,800 --> 00:02:46,750 going to return for us the first HTML page, just called first.html. 61 00:02:46,750 --> 00:02:50,710 Then we have this second route, /second, which is going to return us a second 62 00:02:50,710 --> 00:02:52,930 HTML page, second.html. 63 00:02:52,930 --> 00:02:56,910 And a third route, /third, which is going to return for us a third HTML 64 00:02:56,910 --> 00:02:57,590 page. 65 00:02:57,590 --> 00:02:59,879 In this case, just called third.html. 66 00:02:59,879 --> 00:03:02,920 So it's a very simple page that has three different routes, each of which 67 00:03:02,920 --> 00:03:04,170 will display a different page. 68 00:03:04,170 --> 00:03:05,920 And so if we wanted a web application that 69 00:03:05,920 --> 00:03:07,960 displayed content on three different pages, 70 00:03:07,960 --> 00:03:09,830 this might be how we would do it. 71 00:03:09,830 --> 00:03:14,950 And so if we were to then run this multi-page web application by going 72 00:03:14,950 --> 00:03:18,470 into multi-page and doing a flask run. 73 00:03:18,470 --> 00:03:22,140 And then taking this URL and pasting it into a web browser. 74 00:03:22,140 --> 00:03:23,640 What we get is something like this. 75 00:03:23,640 --> 00:03:25,230 This is the first page. 76 00:03:25,230 --> 00:03:28,330 And if we look at the code for the first page, 77 00:03:28,330 --> 00:03:33,190 we'll go to multi-page and go to the first HTML page. 78 00:03:33,190 --> 00:03:37,920 What we have inside of first is we're extending a layout.html file. 79 00:03:37,920 --> 00:03:40,230 Recall that in Flask when we're generating templates, 80 00:03:40,230 --> 00:03:44,280 we can have HTML files that are extensions of other HTML files 81 00:03:44,280 --> 00:03:46,350 that inherit from them, so to speak, so that we 82 00:03:46,350 --> 00:03:48,766 don't need to repeat ourselves if there's common code that 83 00:03:48,766 --> 00:03:50,620 appears on multiple different pages. 84 00:03:50,620 --> 00:03:55,080 So this first.html file is extending this layout.html file. 85 00:03:55,080 --> 00:03:58,020 And inside the body of the page, just displays a heading 86 00:03:58,020 --> 00:04:02,110 and then the contents that I actually want to display inside of the page. 87 00:04:02,110 --> 00:04:06,300 And if we take a look at this layout file, what we see 88 00:04:06,300 --> 00:04:10,960 is that inside of the web page body, it has this navigation bar, 89 00:04:10,960 --> 00:04:14,082 which is just an unordered list where we have one list item for each 90 00:04:14,082 --> 00:04:15,540 of the pages I might want to go to. 91 00:04:15,540 --> 00:04:18,750 First page, which will link me to the first page, second page, 92 00:04:18,750 --> 00:04:20,170 and third page. 93 00:04:20,170 --> 00:04:22,590 And then this empty body block that eventually I'm 94 00:04:22,590 --> 00:04:27,330 going to fill in with whatever my first.html or second.html or third.html 95 00:04:27,330 --> 00:04:29,480 file wants to include there. 96 00:04:29,480 --> 00:04:33,360 And so in the case of first.html, for instance, that body block 97 00:04:33,360 --> 00:04:37,310 is being filled by this heading and that text. 98 00:04:37,310 --> 00:04:39,890 And so what I get is this first page, where this navigation 99 00:04:39,890 --> 00:04:42,860 bar was defined inside of layout.html. 100 00:04:42,860 --> 00:04:44,840 And then the contents of that page, which 101 00:04:44,840 --> 00:04:48,830 is just defined by my first.html file, which is extending or inheriting 102 00:04:48,830 --> 00:04:50,510 from that layout file. 103 00:04:50,510 --> 00:04:53,590 And then if I click to second page, we'll notice a couple of things. 104 00:04:53,590 --> 00:04:58,370 The URL changes to /second because I've now clicked on a link that took me 105 00:04:58,370 --> 00:05:00,830 to a new route that rendered a different HTML page. 106 00:05:00,830 --> 00:05:03,410 In this case, second.html. 107 00:05:03,410 --> 00:05:05,326 And in the contents of this page, I have a 108 00:05:05,326 --> 00:05:07,700 whatever was inside the second page, which was presumably 109 00:05:07,700 --> 00:05:10,010 some other amount of text. 110 00:05:10,010 --> 00:05:14,600 And likewise, if I click on third page, that takes me to the /third route 111 00:05:14,600 --> 00:05:17,947 and displays the contents of the third page there. 112 00:05:17,947 --> 00:05:19,280 So none of this is anything new. 113 00:05:19,280 --> 00:05:22,357 This is just an extension or looking at how we can use Flask, 114 00:05:22,357 --> 00:05:25,190 as we've already seen it, to be able to link between different pages 115 00:05:25,190 --> 00:05:29,900 and create a web application that has three different routes that take me 116 00:05:29,900 --> 00:05:31,187 to three different pages. 117 00:05:31,187 --> 00:05:33,020 But now let's take a look at how we can give 118 00:05:33,020 --> 00:05:35,930 this same idea of a three-page application 119 00:05:35,930 --> 00:05:38,120 and pull it into a single-page application that's 120 00:05:38,120 --> 00:05:42,290 just a single page that will display all three of the pages worth of content 121 00:05:42,290 --> 00:05:46,050 when I click on the page that I want, in particular. 122 00:05:46,050 --> 00:05:48,840 And so how is that going to work? 123 00:05:48,840 --> 00:05:55,040 Let's take a look at multi-page or single page zero. 124 00:05:55,040 --> 00:05:58,374 And let's look at application.py inside of single-page zero, 125 00:05:58,374 --> 00:06:00,290 which is going to be a single-page application 126 00:06:00,290 --> 00:06:04,130 version of the multi-page application that we've already been creating. 127 00:06:04,130 --> 00:06:06,770 And so the first thing we do at the top is just 128 00:06:06,770 --> 00:06:11,600 define a default route that is going to return index.html. 129 00:06:11,600 --> 00:06:14,280 And we'll see what's inside of index.html in just a moment. 130 00:06:14,280 --> 00:06:18,890 But for now, it's just going to be returning for us some HTML file. 131 00:06:18,890 --> 00:06:22,100 But then down below, we have a couple interesting things going on. 132 00:06:22,100 --> 00:06:24,740 Starting on line 9, I define a variable called 133 00:06:24,740 --> 00:06:30,170 texts, which is just going to be a list in Python of three different strings. 134 00:06:30,170 --> 00:06:34,147 Where on this first line, that's what I want to appear on the first page. 135 00:06:34,147 --> 00:06:36,980 On the second line, that's what I want to appear on the second page. 136 00:06:36,980 --> 00:06:40,730 And on this third line, this is what I want to appear on the third page. 137 00:06:40,730 --> 00:06:47,090 And then down below, I have these three routes, /first, /second, and /third, 138 00:06:47,090 --> 00:06:49,610 each of which returns a different one of those strings. 139 00:06:49,610 --> 00:06:53,759 Notice I'm not returning a whole HTML file that has a header with a title, 140 00:06:53,759 --> 00:06:56,300 and then the navigation bar, and then the text underneath it. 141 00:06:56,300 --> 00:06:59,850 I'm just returning the string that I care about for that particular page. 142 00:06:59,850 --> 00:07:02,810 So in /first, I'm just returning that string-- 143 00:07:02,810 --> 00:07:05,010 that first item in my list of texts. 144 00:07:05,010 --> 00:07:09,320 /second returns me the second item of index1 in my list of texts. 145 00:07:09,320 --> 00:07:14,420 And likewise, /third will take me to item at index 2 which is the last item 146 00:07:14,420 --> 00:07:16,160 in my list of texts. 147 00:07:16,160 --> 00:07:18,590 And so far, this seems like a lot of added complexity. 148 00:07:18,590 --> 00:07:20,570 How does this all tie together now? 149 00:07:20,570 --> 00:07:25,310 Let's take a look at index.html and see how we might actually 150 00:07:25,310 --> 00:07:28,590 use this inside of an HTML file. 151 00:07:28,590 --> 00:07:30,577 So what I have inside of index.html-- 152 00:07:30,577 --> 00:07:32,660 I'm skipping the JavaScript for now and just going 153 00:07:32,660 --> 00:07:35,100 to the HTML contents of this page. 154 00:07:35,100 --> 00:07:38,600 I have this navigation bar, which looks similar to before. 155 00:07:38,600 --> 00:07:40,657 It's an unordered list, where each list item 156 00:07:40,657 --> 00:07:43,490 is going to be a link that I can click on-- first page, second page, 157 00:07:43,490 --> 00:07:44,510 third page. 158 00:07:44,510 --> 00:07:49,430 But unlike the multi-page application, what's different about these links? 159 00:07:49,430 --> 00:07:52,549 Anything immediately strike you as different 160 00:07:52,549 --> 00:07:53,840 compared to what we had before? 161 00:07:53,840 --> 00:07:57,886 162 00:07:57,886 --> 00:07:58,600 Yeah? 163 00:07:58,600 --> 00:08:00,040 AUDIENCE: [INAUDIBLE] URL. 164 00:08:00,040 --> 00:08:03,670 BRIAN YU: Yeah, I don't have a URL these href attributes that would normally 165 00:08:03,670 --> 00:08:06,730 be the link of the page that I want to go to when I click on that link, 166 00:08:06,730 --> 00:08:07,810 those are missing. 167 00:08:07,810 --> 00:08:10,150 They're just empty strings for right now. 168 00:08:10,150 --> 00:08:13,060 And notice also I've given them all a class and called them nav-link. 169 00:08:13,060 --> 00:08:15,140 We'll see why that's important in just a moment. 170 00:08:15,140 --> 00:08:16,570 And then I have the body of the page, which 171 00:08:16,570 --> 00:08:17,986 for now is just going to be empty. 172 00:08:17,986 --> 00:08:19,880 There is nothing inside the body of the page. 173 00:08:19,880 --> 00:08:23,080 So how does this get filled and how do these links end up working 174 00:08:23,080 --> 00:08:25,120 if none of them seem to link anywhere? 175 00:08:25,120 --> 00:08:27,440 They have an empty href attribute. 176 00:08:27,440 --> 00:08:29,345 Well, that's where the JavaScript comes in. 177 00:08:29,345 --> 00:08:31,720 And so let's take a look at some of this JavaScript code, 178 00:08:31,720 --> 00:08:35,690 starting with this function here called loadPage. 179 00:08:35,690 --> 00:08:39,190 So this is a JavaScript function called load page, which takes as its argument 180 00:08:39,190 --> 00:08:42,380 a name, and that's going to be presumably the name of the page that I 181 00:08:42,380 --> 00:08:45,130 want to load-- the first page, the second page, or the third page, 182 00:08:45,130 --> 00:08:46,300 for instance. 183 00:08:46,300 --> 00:08:49,692 And so what we see in here is reminiscent of what we did during last 184 00:08:49,692 --> 00:08:51,400 lecture, when we were talking about AJAX, 185 00:08:51,400 --> 00:08:54,850 about trying to get additional information from the server when 186 00:08:54,850 --> 00:08:58,330 my index.html file wants to load, the first page-- 187 00:08:58,330 --> 00:09:01,060 get that first string of text from the server-- 188 00:09:01,060 --> 00:09:03,760 well, my index.html file right now doesn't know anything 189 00:09:03,760 --> 00:09:06,610 about what that first piece of text is. 190 00:09:06,610 --> 00:09:09,700 So I'm going to need to ask the Flask server for information 191 00:09:09,700 --> 00:09:11,170 about what it is. 192 00:09:11,170 --> 00:09:15,160 So in order to do that, I create a new HTTP request just like so. 193 00:09:15,160 --> 00:09:17,200 I'm going to create GET request. 194 00:09:17,200 --> 00:09:19,630 And what route am I going to make the GET requests to? 195 00:09:19,630 --> 00:09:23,230 It's going to be to slash and then recall that this dollar sign and curly 196 00:09:23,230 --> 00:09:28,150 brace syntax is the template literal syntax in JavaScript ES6, which 197 00:09:28,150 --> 00:09:31,600 basically says plug-in the value of the variable name here. 198 00:09:31,600 --> 00:09:36,040 And so if I'm trying to load_page where the page is first-- the first page-- 199 00:09:36,040 --> 00:09:40,370 then what I'm really going to be doing is making a GET request to /first-- 200 00:09:40,370 --> 00:09:44,730 the URL /first-- which we defined inside of application.py earlier. 201 00:09:44,730 --> 00:09:46,720 We can go back to that in a moment. 202 00:09:46,720 --> 00:09:50,560 When that request is done, here's the function that I want to run. 203 00:09:50,560 --> 00:09:53,590 First, get the response text-- whatever came back from the server 204 00:09:53,590 --> 00:09:55,620 when I made this call to the server. 205 00:09:55,620 --> 00:09:58,270 Save it inside of a variable called response. 206 00:09:58,270 --> 00:10:02,620 And then take the body of my HTML page. 207 00:10:02,620 --> 00:10:05,440 Remember, querySelector will search through my document, 208 00:10:05,440 --> 00:10:09,580 finding me something that has ID called body 209 00:10:09,580 --> 00:10:13,750 and then filling in the inner HTML of that body 210 00:10:13,750 --> 00:10:17,680 block with whatever that response is-- whatever this variable response is-- 211 00:10:17,680 --> 00:10:21,160 which is whatever text came back from the request. 212 00:10:21,160 --> 00:10:24,400 So this function now will allow me to load any of those pages-- 213 00:10:24,400 --> 00:10:26,710 that first page, the second page, or third page, 214 00:10:26,710 --> 00:10:32,100 get the contents from the server, and then just fill it in to the body block. 215 00:10:32,100 --> 00:10:34,710 Then when is this function actually used? 216 00:10:34,710 --> 00:10:37,530 Well, it's used in a couple of places. 217 00:10:37,530 --> 00:10:41,280 What we have here is that when the done content is loaded, 218 00:10:41,280 --> 00:10:45,570 when my web application is done loading, the first thing that I'm going to do 219 00:10:45,570 --> 00:10:46,982 is load_page first. 220 00:10:46,982 --> 00:10:48,690 Call this load_page function that's going 221 00:10:48,690 --> 00:10:53,762 to get me information from the server and go ahead and load the first page. 222 00:10:53,762 --> 00:10:55,720 But then in addition to loading the first page, 223 00:10:55,720 --> 00:10:57,390 the next thing that I need to do is make sure 224 00:10:57,390 --> 00:10:59,760 that when I click on any of those links, those links 225 00:10:59,760 --> 00:11:02,010 will load the subsequent pages. 226 00:11:02,010 --> 00:11:04,410 And so I'm going to do a querySelectorAll, 227 00:11:04,410 --> 00:11:07,650 selecting for all of the things that have a class of nav-link. 228 00:11:07,650 --> 00:11:09,180 Recall the done below. 229 00:11:09,180 --> 00:11:12,932 I said that each one of these URLs has a class nav-link. 230 00:11:12,932 --> 00:11:14,640 So if I want to select all those links, I 231 00:11:14,640 --> 00:11:17,070 can just select for everything that has class nav-link. 232 00:11:17,070 --> 00:11:21,900 And now I've got a JavaScript array of all of those individual links. 233 00:11:21,900 --> 00:11:27,000 And for each of those individual links, I want to apply some logic 234 00:11:27,000 --> 00:11:29,130 and here's the logic that I'm going to apply. 235 00:11:29,130 --> 00:11:33,000 Namely, when that link is clicked on, on the click event, 236 00:11:33,000 --> 00:11:35,130 I'm going to run this function where I'm going 237 00:11:35,130 --> 00:11:39,240 to load the page link.dataset.page. 238 00:11:39,240 --> 00:11:42,360 And recall that link.dataset.page is going 239 00:11:42,360 --> 00:11:48,150 to get me whatever the data-page attribute is of this particular link 240 00:11:48,150 --> 00:11:50,130 because I can use the data attributes to be 241 00:11:50,130 --> 00:11:54,130 able to store whatever information I want associated with these links. 242 00:11:54,130 --> 00:11:57,610 So each of these links is going to store for me which route I want to access. 243 00:11:57,610 --> 00:12:00,660 In this case, first and second and third. 244 00:12:00,660 --> 00:12:03,400 And so how does this actually work in practice? 245 00:12:03,400 --> 00:12:07,500 Well, if I go ahead and go into single-page zero 246 00:12:07,500 --> 00:12:13,180 and run this application, what I get at first is just the first page. 247 00:12:13,180 --> 00:12:18,690 Now recall that originally the body here-- this body of the page is empty. 248 00:12:18,690 --> 00:12:21,360 And yet, when I load the page, it fills automatically 249 00:12:21,360 --> 00:12:23,990 with the contents of that first piece of text. 250 00:12:23,990 --> 00:12:25,740 And the reason why that was able to happen 251 00:12:25,740 --> 00:12:27,960 is because immediately when the DOM is done loading, 252 00:12:27,960 --> 00:12:32,120 I called load_page first to say load the contents of the first page, 253 00:12:32,120 --> 00:12:34,980 asked the server for whatever the contents of the first page is, 254 00:12:34,980 --> 00:12:36,900 and then plug it into the body. 255 00:12:36,900 --> 00:12:38,880 And now if I click on the second page, then I 256 00:12:38,880 --> 00:12:40,379 see the contents of the second page. 257 00:12:40,379 --> 00:12:41,910 The third page on the third page. 258 00:12:41,910 --> 00:12:45,337 And never am I making a request for a brand new page. 259 00:12:45,337 --> 00:12:47,670 I'm just pulling information that I need from the server 260 00:12:47,670 --> 00:12:50,070 and plugging it in to where I need it. 261 00:12:50,070 --> 00:12:52,200 And so why might this single-page approach 262 00:12:52,200 --> 00:12:54,690 be advantageous over a multi-page approach, 263 00:12:54,690 --> 00:12:56,730 like the one we saw at the very beginning? 264 00:12:56,730 --> 00:12:59,070 What advantages does this have that might make 265 00:12:59,070 --> 00:13:00,630 it useful for some web applications? 266 00:13:00,630 --> 00:13:02,964 AUDIENCE: We don't have to reload the web page. 267 00:13:02,964 --> 00:13:05,130 BRIAN YU: Exactly, we don't need to reload the page. 268 00:13:05,130 --> 00:13:08,910 So if there is a lot of content on this page that isn't changing, for example, 269 00:13:08,910 --> 00:13:12,684 this navigation bar just really stays the same, no matter which page I'm on. 270 00:13:12,684 --> 00:13:15,600 Then I don't need to constantly be reloading the entirety of the page. 271 00:13:15,600 --> 00:13:18,870 All the HTML header information and this navigation bar information-- 272 00:13:18,870 --> 00:13:22,020 I can just load the actual information that needs to change. 273 00:13:22,020 --> 00:13:24,000 In this case, namely just the text that is 274 00:13:24,000 --> 00:13:27,430 going to appear in the actual content of the page. 275 00:13:27,430 --> 00:13:29,120 So that's certainly one advantage. 276 00:13:29,120 --> 00:13:30,330 What's a disadvantage? 277 00:13:30,330 --> 00:13:33,074 Why might this single-page approach be not as good? 278 00:13:33,074 --> 00:13:34,990 Or what's something that I lose in doing this? 279 00:13:34,990 --> 00:13:41,808 280 00:13:41,808 --> 00:13:43,269 Yeah? 281 00:13:43,269 --> 00:13:46,678 AUDIENCE: [INAUDIBLE] could be wrong. 282 00:13:46,678 --> 00:13:48,626 I just waste [INAUDIBLE]. 283 00:13:48,626 --> 00:13:51,021 284 00:13:51,021 --> 00:13:54,020 BRIAN YU: Yeah, so this might be a little bit of overkill, for instance. 285 00:13:54,020 --> 00:13:55,760 An example like this, certainly it might be, 286 00:13:55,760 --> 00:13:57,310 where I'm just loading an individual paragraphs. 287 00:13:57,310 --> 00:13:59,143 And it wouldn't have been all that much work 288 00:13:59,143 --> 00:14:00,800 to load the entirety of the HTML page. 289 00:14:00,800 --> 00:14:03,910 So that's certainly one trade-off to be watching as well. 290 00:14:03,910 --> 00:14:07,140 And one thing you may notice in terms of how this page operates differently 291 00:14:07,140 --> 00:14:09,170 than the multi-page approach is that recall 292 00:14:09,170 --> 00:14:11,370 in the multi-page approach, when I clicked 293 00:14:11,370 --> 00:14:13,710 on an individual link, the URL changed. 294 00:14:13,710 --> 00:14:17,840 The URL when I clicked on the second page, took me to /second as the URL. 295 00:14:17,840 --> 00:14:21,060 And when I clicked on the third page, that took me to /third whereas here 296 00:14:21,060 --> 00:14:24,790 in this single-page approach, when I click on individual links, 297 00:14:24,790 --> 00:14:27,420 notice that up here in the URL bar, nothing's changing. 298 00:14:27,420 --> 00:14:30,900 I'm staying on the same page and so the URL doesn't necessarily change. 299 00:14:30,900 --> 00:14:32,430 And maybe that's what you want. 300 00:14:32,430 --> 00:14:34,320 But maybe in many other applications, it's 301 00:14:34,320 --> 00:14:37,080 useful for the user of the web application 302 00:14:37,080 --> 00:14:40,431 to be able to see the URL as an indication of where they are 303 00:14:40,431 --> 00:14:41,930 in terms of navigating your website. 304 00:14:41,930 --> 00:14:46,230 It might be helpful for the user to see a /second up in the URL so that they 305 00:14:46,230 --> 00:14:49,950 know, in fact, that they are on the second page or see /third to know that 306 00:14:49,950 --> 00:14:51,236 they are on the third page. 307 00:14:51,236 --> 00:14:53,610 And a lot of users will utilize that URL for that purpose 308 00:14:53,610 --> 00:14:57,210 of providing that additional information and context about where they currently 309 00:14:57,210 --> 00:14:58,240 are. 310 00:14:58,240 --> 00:15:01,370 And so how can we recreate that functionality 311 00:15:01,370 --> 00:15:04,470 of allowing for the URL to change without actually 312 00:15:04,470 --> 00:15:06,060 needing to reload the whole page? 313 00:15:06,060 --> 00:15:10,310 Well, luckily, in the latest version of HTML, HTML5, 314 00:15:10,310 --> 00:15:15,570 we have access to what's called the HTML5 History API, which 315 00:15:15,570 --> 00:15:21,030 is a feature of HTML5 that allows us to manipulate the browser's 316 00:15:21,030 --> 00:15:25,830 history effectively and update the URL to reflect different URLs that I might 317 00:15:25,830 --> 00:15:27,120 want to create. 318 00:15:27,120 --> 00:15:34,380 And so the way that this works is that we can push URL states into the web 319 00:15:34,380 --> 00:15:35,460 browser's history. 320 00:15:35,460 --> 00:15:38,550 So I might start out on the /first route. 321 00:15:38,550 --> 00:15:41,070 And when the user clicks on the second link, that 322 00:15:41,070 --> 00:15:44,550 takes me to presumably the second page, even in a single-page application, 323 00:15:44,550 --> 00:15:51,480 even if I'm not trying to access some new HTML page, I can, using JavaScript, 324 00:15:51,480 --> 00:15:54,720 tell the web browser that I want to update the URL. 325 00:15:54,720 --> 00:15:57,840 Push this new state that I want to be at URLs /second. 326 00:15:57,840 --> 00:16:01,637 And likewise, when I click on the third link, I can push this new URL, /third, 327 00:16:01,637 --> 00:16:04,470 so that I can update the URL, depending on what the user is clicking 328 00:16:04,470 --> 00:16:07,920 on or depending on what's happening inside my application at any given time 329 00:16:07,920 --> 00:16:10,750 in order to allow for this additional functionality. 330 00:16:10,750 --> 00:16:13,320 So let's take a look at how we might expand 331 00:16:13,320 --> 00:16:16,800 upon this single-page application idea to be able to allow 332 00:16:16,800 --> 00:16:19,930 for changing the state of the URL. 333 00:16:19,930 --> 00:16:26,260 So let's now look at single page one and look at index.html there. 334 00:16:26,260 --> 00:16:31,560 So most of this is ultimately the same, but there are a couple of differences. 335 00:16:31,560 --> 00:16:36,690 In particular, when inside of my load_page function when 336 00:16:36,690 --> 00:16:40,890 I'm trying to load a new page from the server, when the request is downloading 337 00:16:40,890 --> 00:16:43,950 after I fill in whatever information I got from the server 338 00:16:43,950 --> 00:16:47,250 into the body block of HTML page, now what I want to do is 339 00:16:47,250 --> 00:16:49,380 I want to update the URL. 340 00:16:49,380 --> 00:16:51,130 And so I'm going to do a couple of things. 341 00:16:51,130 --> 00:16:53,880 The first thing that I'm doing-- and this is just for good measure 342 00:16:53,880 --> 00:16:56,140 aesthetically-- is that every web page has a title. 343 00:16:56,140 --> 00:16:58,950 It's the thing that appears at the top of the web page and the web browser. 344 00:16:58,950 --> 00:17:01,241 And so I might want to update the title of the web page 345 00:17:01,241 --> 00:17:02,780 to reflect the new page that I'm on. 346 00:17:02,780 --> 00:17:05,900 And so I can just set that by using document-title to get 347 00:17:05,900 --> 00:17:08,430 at whatever I want to call the page. 348 00:17:08,430 --> 00:17:13,740 And then history.pushstate is how I manipulate the HTML5 history 349 00:17:13,740 --> 00:17:17,339 by saying I want to push a new URL, in particular. 350 00:17:17,339 --> 00:17:20,720 The first argument here is any data that I 351 00:17:20,720 --> 00:17:24,400 want associated with me pushing this new URL, and we'll see in a moment 352 00:17:24,400 --> 00:17:25,650 why that's going to be useful. 353 00:17:25,650 --> 00:17:26,980 But for now, we don't really care about it. 354 00:17:26,980 --> 00:17:28,260 So we'll just call it null. 355 00:17:28,260 --> 00:17:32,700 The second argument is the title of the page that we're trying to push. 356 00:17:32,700 --> 00:17:35,267 And the third argument, in particular, is the URL 357 00:17:35,267 --> 00:17:36,600 that we're going to try to push. 358 00:17:36,600 --> 00:17:38,970 In this case, the title and the URL are the same. 359 00:17:38,970 --> 00:17:41,160 But this is ultimately what is going to affect 360 00:17:41,160 --> 00:17:46,160 what URL gets changed on the URL bar at the top of the web browser. 361 00:17:46,160 --> 00:17:50,520 And so using just this line, I'm able to update the current URL 362 00:17:50,520 --> 00:17:54,170 that I'm at in order to reflect whatever page that I happen to be on. 363 00:17:54,170 --> 00:18:02,190 And so if I go into single page one and run this application, 364 00:18:02,190 --> 00:18:06,300 what I get is I start out on /first immediately. 365 00:18:06,300 --> 00:18:08,030 And so my URL is /first. 366 00:18:08,030 --> 00:18:12,900 And notice that when I click on second page, the URL changes to /second-- 367 00:18:12,900 --> 00:18:16,140 almost as if I had clicked and gone to an entirely different page when 368 00:18:16,140 --> 00:18:20,460 in actuality, all that was happening was that inside of the code here, 369 00:18:20,460 --> 00:18:23,400 after I loaded the second contents of the second page, 370 00:18:23,400 --> 00:18:29,830 filled it into the body, I pushed this /second route to my history. 371 00:18:29,830 --> 00:18:33,310 And as a result, the URL is updated to reflect that. 372 00:18:33,310 --> 00:18:35,310 And so that allows us to update the URL in order 373 00:18:35,310 --> 00:18:39,930 to make it reflect whatever we want, but this isn't quite perfect. 374 00:18:39,930 --> 00:18:43,650 Any ideas as to what might not work about this 375 00:18:43,650 --> 00:18:46,830 pushing different things to the URL and expecting the user 376 00:18:46,830 --> 00:18:53,175 to have a similar behavior to as if this were a multiple page application? 377 00:18:53,175 --> 00:18:55,300 AUDIENCE: Does the Back button work on the browser? 378 00:18:55,300 --> 00:18:55,960 BRIAN YU: Yeah, great question. 379 00:18:55,960 --> 00:18:56,960 Does the Back button work? 380 00:18:56,960 --> 00:18:58,710 What happens when I press the Back button? 381 00:18:58,710 --> 00:19:01,870 Well, in this case, if I press the Back button, I go back to /first. , 382 00:19:01,870 --> 00:19:05,560 Certainly, the URL changed, but nothing changed on the page. 383 00:19:05,560 --> 00:19:07,174 I stayed on the second page. 384 00:19:07,174 --> 00:19:08,590 So I clicked the second page link. 385 00:19:08,590 --> 00:19:10,000 The second page loaded. 386 00:19:10,000 --> 00:19:13,720 But as soon as I clicked the Back button, the URL changed back to /first, 387 00:19:13,720 --> 00:19:18,460 but the contents of the page stayed on the second page because nothing 388 00:19:18,460 --> 00:19:21,160 in my JavaScript code, of my index.html page, 389 00:19:21,160 --> 00:19:24,700 says anything about what to do when the Back button is pressed. 390 00:19:24,700 --> 00:19:25,780 What should happen then? 391 00:19:25,780 --> 00:19:26,680 We don't really know. 392 00:19:26,680 --> 00:19:28,190 So that's going to be the next step. 393 00:19:28,190 --> 00:19:30,460 How do we fix that in order to allow ourselves 394 00:19:30,460 --> 00:19:34,720 a situation where we can allow the back and forward buttons on our web browser 395 00:19:34,720 --> 00:19:37,010 to work as we would expect them to? 396 00:19:37,010 --> 00:19:40,960 So the idea here is that after we go to first, second, third, 397 00:19:40,960 --> 00:19:44,680 when we want to go back, for instance, to the previous page, 398 00:19:44,680 --> 00:19:47,764 if we think of this set of URLs as a stack-- just one link, 399 00:19:47,764 --> 00:19:49,930 followed by another link, followed by another link-- 400 00:19:49,930 --> 00:19:52,270 when we go back, that's effectively popping 401 00:19:52,270 --> 00:19:55,150 whatever was on the top of the stack off the stack. 402 00:19:55,150 --> 00:19:58,300 And so now we're no longer on the third page, but we're on the second page 403 00:19:58,300 --> 00:19:59,230 instead. 404 00:19:59,230 --> 00:20:03,430 So we went from first, second, third to just first and second. 405 00:20:03,430 --> 00:20:07,630 And in order to do that, we're going to use an additional feature of the HTML5 406 00:20:07,630 --> 00:20:08,770 History API. 407 00:20:08,770 --> 00:20:11,410 We used push state as a JavaScript function 408 00:20:11,410 --> 00:20:15,070 that allowed us to add some new URL to the stack to update 409 00:20:15,070 --> 00:20:17,140 whatever the URL was in the URL bar. 410 00:20:17,140 --> 00:20:20,950 But we're now also going to handle the popstate event. 411 00:20:20,950 --> 00:20:23,770 What happens when I try and pop something off the stack? 412 00:20:23,770 --> 00:20:26,710 What happens when I try and click the Back button in order to go back 413 00:20:26,710 --> 00:20:28,540 to whatever page I was on before? 414 00:20:28,540 --> 00:20:30,620 How do we handle that situation? 415 00:20:30,620 --> 00:20:35,100 And so we handle that in a single page too. 416 00:20:35,100 --> 00:20:38,680 So let's open up index.html for single page 2. 417 00:20:38,680 --> 00:20:42,110 And so inside of this load_page function, 418 00:20:42,110 --> 00:20:47,050 when I push the state, as I did before, in addition to pushing information 419 00:20:47,050 --> 00:20:51,490 about what the title of the page is and what the URL of the page is, 420 00:20:51,490 --> 00:20:54,970 I'm also going to take advantage of the fact that when I push State, 421 00:20:54,970 --> 00:20:56,710 I can push data on top this stack. 422 00:20:56,710 --> 00:21:00,280 I can store information about this page that might be relevant 423 00:21:00,280 --> 00:21:02,330 if I ever later need to go back. 424 00:21:02,330 --> 00:21:07,060 So in this case, what information do I need to store about this page in case 425 00:21:07,060 --> 00:21:08,590 I ever need to go back to it? 426 00:21:08,590 --> 00:21:11,890 Well, I'm going to store this JavaScript object that has two values in it. 427 00:21:11,890 --> 00:21:14,530 One is whatever the title of the page is, 428 00:21:14,530 --> 00:21:18,010 which is just this name value, which is going to be first, second, or third. 429 00:21:18,010 --> 00:21:21,400 And the second thing that I care about is storing the actual text 430 00:21:21,400 --> 00:21:23,140 content of what was on this page. 431 00:21:23,140 --> 00:21:25,870 Whatever came back in this variable responds 432 00:21:25,870 --> 00:21:29,320 this is information that I will need to know in case I ever go back. 433 00:21:29,320 --> 00:21:32,830 Because if I go to the second page, and I fill in the contents of the HTML page 434 00:21:32,830 --> 00:21:36,940 with the second paragraph, and I go back to the first page, well, 435 00:21:36,940 --> 00:21:41,320 I need my web page now to know what text to fill in to the first page. 436 00:21:41,320 --> 00:21:43,930 And that information would have been lost if I 437 00:21:43,930 --> 00:21:45,760 hadn't tried to store it somewhere. 438 00:21:45,760 --> 00:21:48,550 And so by taking advantage of this data that I 439 00:21:48,550 --> 00:21:51,040 can associate with history.pushstate, this 440 00:21:51,040 --> 00:21:55,060 allows me to store this data with the URL that I'm pushing. 441 00:21:55,060 --> 00:21:57,772 And now when the state is popped-- 442 00:21:57,772 --> 00:22:00,730 in other words, when someone presses the Back button on the web browser 443 00:22:00,730 --> 00:22:03,670 to go back to whatever page they were on previously, 444 00:22:03,670 --> 00:22:06,830 then this is what's going to happen. 445 00:22:06,830 --> 00:22:08,830 So we're going to handle this popstate. 446 00:22:08,830 --> 00:22:12,430 When someone, on the window, tries to popstate-- in other words, 447 00:22:12,430 --> 00:22:14,380 press the Back button on this window-- 448 00:22:14,380 --> 00:22:16,520 here's the function that should run. 449 00:22:16,520 --> 00:22:20,110 I get as a parameter, e, for the event that just took place, 450 00:22:20,110 --> 00:22:25,250 and I can get the state of whatever was just popped off with e.state. 451 00:22:25,250 --> 00:22:27,360 And so I'm going to store that inside of data. 452 00:22:27,360 --> 00:22:30,400 And so this data is going to be that JavaScript 453 00:22:30,400 --> 00:22:33,670 object that contained a title, and that contained 454 00:22:33,670 --> 00:22:35,954 the text that I wanted on that page. 455 00:22:35,954 --> 00:22:37,870 And so what should I do with that information? 456 00:22:37,870 --> 00:22:40,060 Well, with data.title, that title that got 457 00:22:40,060 --> 00:22:42,370 pushed onto the stack, well that should become 458 00:22:42,370 --> 00:22:44,470 the new title of my HTML document. 459 00:22:44,470 --> 00:22:48,254 So I'm going to set document.title to be whatever that title was. 460 00:22:48,254 --> 00:22:49,920 And then what should I do with the text? 461 00:22:49,920 --> 00:22:53,560 Well, when I go back to that first page, whatever that first page's text was, 462 00:22:53,560 --> 00:22:56,470 whatever was inside of data.text, that's what I want 463 00:22:56,470 --> 00:22:59,110 to fill in to the body of my HTML page. 464 00:22:59,110 --> 00:23:01,900 So I go document.querySelector body to get 465 00:23:01,900 --> 00:23:04,360 whatever the body block of that web page is, and I 466 00:23:04,360 --> 00:23:07,630 fill in the inner HTML of that HTML element 467 00:23:07,630 --> 00:23:10,654 with whatever that text response was. 468 00:23:10,654 --> 00:23:13,570 And so what all of this is going to do, and what all of this is saying 469 00:23:13,570 --> 00:23:17,440 is that if I ever press the Back button, this onpopstate event, 470 00:23:17,440 --> 00:23:20,470 then get the information associated with that page, 471 00:23:20,470 --> 00:23:24,040 e.state, the state that I'm trying to go back to, 472 00:23:24,040 --> 00:23:26,560 take the title of that, set that to be the document's title, 473 00:23:26,560 --> 00:23:30,460 and then fill in the body of the page with the text of whatever was 474 00:23:30,460 --> 00:23:33,770 on inside of that JavaScript object. 475 00:23:33,770 --> 00:23:36,370 And so how does that manifest itself in practice? 476 00:23:36,370 --> 00:23:45,230 If I now try to go into single page 2 and run that application, 477 00:23:45,230 --> 00:23:47,110 now I start on the first page. 478 00:23:47,110 --> 00:23:50,500 And if I go to the second page, I go to /second. 479 00:23:50,500 --> 00:23:53,990 And notice, in particular, the title updates to be second. 480 00:23:53,990 --> 00:23:57,490 This is document.title, the title of the web page. 481 00:23:57,490 --> 00:23:59,990 And if I click on third, now I'm on the third page. 482 00:23:59,990 --> 00:24:04,230 And notice the documents title also updates to be third now. 483 00:24:04,230 --> 00:24:05,970 And now if I click Back-- 484 00:24:05,970 --> 00:24:08,640 I've built up this stack first, second, third. 485 00:24:08,640 --> 00:24:12,900 If I click the Back button, that's going to pop third off the top of the stock. 486 00:24:12,900 --> 00:24:15,180 And now what I'm left with is second, and that's 487 00:24:15,180 --> 00:24:18,820 going to trigger that onpopstate event, which does two things. 488 00:24:18,820 --> 00:24:22,560 The first thing it does is it changes document.title to be whatever 489 00:24:22,560 --> 00:24:24,740 the title was-- in this case, second. 490 00:24:24,740 --> 00:24:28,620 And it changes the text of this page-- whatever was inside that ID body 491 00:24:28,620 --> 00:24:29,460 block-- 492 00:24:29,460 --> 00:24:33,660 to be whatever the text was stored inside of that JavaScript object. 493 00:24:33,660 --> 00:24:34,660 And I can go back again. 494 00:24:34,660 --> 00:24:37,370 I go back, and now I'm on the first page. 495 00:24:37,370 --> 00:24:40,150 And the first page's text is there as well. 496 00:24:40,150 --> 00:24:42,960 So by taking advantage of the HTML5 History API, 497 00:24:42,960 --> 00:24:45,300 the ability to manipulate URLs, the ability 498 00:24:45,300 --> 00:24:47,280 to use this popstate event to figure out what 499 00:24:47,280 --> 00:24:49,230 should happen when the Back button is pressed. 500 00:24:49,230 --> 00:24:51,930 We can begin to create these single-page applications that 501 00:24:51,930 --> 00:24:54,390 allow the user to stay on the same page and just pull 502 00:24:54,390 --> 00:24:57,180 in whatever data from the server we need without actually needing 503 00:24:57,180 --> 00:24:59,430 to reload the page and reload any of the content 504 00:24:59,430 --> 00:25:00,810 that we already had on the page. 505 00:25:00,810 --> 00:25:02,952 Again, if we ever were to need it. 506 00:25:02,952 --> 00:25:04,410 Questions about any of that so far? 507 00:25:04,410 --> 00:25:07,369 AUDIENCE: What happens if you press the forward button? 508 00:25:07,369 --> 00:25:08,410 BRIAN YU: Great question. 509 00:25:08,410 --> 00:25:10,190 What happens if I press forward? 510 00:25:10,190 --> 00:25:13,050 So if I press forward, it sort of does the same thing in reverse. 511 00:25:13,050 --> 00:25:15,610 So it keeps track of not only the previous states 512 00:25:15,610 --> 00:25:19,840 that I was in but also in the states that I went back from, 513 00:25:19,840 --> 00:25:21,760 such that if I press forward, now it's going 514 00:25:21,760 --> 00:25:23,890 to get me whatever I just popped off the stack 515 00:25:23,890 --> 00:25:25,670 and sort of bring that back for me. 516 00:25:25,670 --> 00:25:29,200 And so now the title updates the second, and the text updates the second. 517 00:25:29,200 --> 00:25:32,410 And that's all again because of that same onpopstate event. 518 00:25:32,410 --> 00:25:36,190 So the backwards and forwards buttons will work exactly as intended-- 519 00:25:36,190 --> 00:25:38,430 great question. 520 00:25:38,430 --> 00:25:40,590 OK, we'll change gears a little bit. 521 00:25:40,590 --> 00:25:43,942 And we'll start to talk more about this idea of the window and the document 522 00:25:43,942 --> 00:25:45,150 that we've been dealing with. 523 00:25:45,150 --> 00:25:48,960 So we've dealt with this window and document variables a fair bit, 524 00:25:48,960 --> 00:25:51,600 where we did window.onpopstate just now to say here's 525 00:25:51,600 --> 00:25:53,100 what should happen when you go back. 526 00:25:53,100 --> 00:25:57,090 And we've used this document variable a whole lot to try and use querySelector 527 00:25:57,090 --> 00:25:58,830 to try and extract information. 528 00:25:58,830 --> 00:26:03,600 Window and document are just examples of these JavaScript objects 529 00:26:03,600 --> 00:26:06,600 that we can perform operations on and access properties of. 530 00:26:06,600 --> 00:26:11,220 And in particular, we have access to information about their size 531 00:26:11,220 --> 00:26:13,150 and about their position. 532 00:26:13,150 --> 00:26:20,310 So for instance, if we take a look at this example here. 533 00:26:20,310 --> 00:26:22,200 This is just a generic window. 534 00:26:22,200 --> 00:26:24,600 If I wanted to get the size of this window-- 535 00:26:24,600 --> 00:26:27,450 the size of various components of this window-- 536 00:26:27,450 --> 00:26:30,630 well, window.innerwidth would be a variable 537 00:26:30,630 --> 00:26:34,590 that I could use to get for me whatever the width of the window 538 00:26:34,590 --> 00:26:36,330 is, just in terms of number of pixels. 539 00:26:36,330 --> 00:26:39,450 I can use that information to get at the width of the window. 540 00:26:39,450 --> 00:26:44,340 And likewise, I can use a window.innerheight 541 00:26:44,340 --> 00:26:47,620 to be able to extract for me whatever the height of the window is. 542 00:26:47,620 --> 00:26:50,910 So just in terms of number of pixels, how tall is the window. 543 00:26:50,910 --> 00:26:53,490 But of course, the window is not displaying 544 00:26:53,490 --> 00:26:55,860 the entirety of the HTML page. 545 00:26:55,860 --> 00:26:59,460 If I have a long HTML page that I would need to scroll through presumably, 546 00:26:59,460 --> 00:27:02,010 then what I really have is this longer document. 547 00:27:02,010 --> 00:27:04,350 This gray area you can think of is just the document, 548 00:27:04,350 --> 00:27:08,520 where inside of the document, only a potentially small component 549 00:27:08,520 --> 00:27:11,940 of that document is actually visible inside of the window. 550 00:27:11,940 --> 00:27:14,670 And so there are other properties you can access as well in order 551 00:27:14,670 --> 00:27:16,710 to get at information about the document. 552 00:27:16,710 --> 00:27:21,660 So document.body.offsetHeight offsetHeight 553 00:27:21,660 --> 00:27:25,150 will get you the displacement height of any HTML element. 554 00:27:25,150 --> 00:27:28,590 And so the offsetHeight of the body of the HTML page just gets me-- 555 00:27:28,590 --> 00:27:31,110 really the entire height of this entire document-- 556 00:27:31,110 --> 00:27:34,360 of which the window's height is probably only a small portion of that. 557 00:27:34,360 --> 00:27:38,220 And likewise, I can also access variables like window.dot.scrollY 558 00:27:38,220 --> 00:27:42,630 to say how far down along the page am I currently scrolled? 559 00:27:42,630 --> 00:27:45,510 If I scrolled down 50 pixels window.dot.scrollY 560 00:27:45,510 --> 00:27:47,310 will be 50, for instance. 561 00:27:47,310 --> 00:27:49,560 And so you can use all of this information 562 00:27:49,560 --> 00:27:54,510 to be able to look at the current pixel values of things about your window. 563 00:27:54,510 --> 00:27:56,820 And this is helpful if you ever want to use information 564 00:27:56,820 --> 00:27:59,280 about where the user scrolled on a page are 565 00:27:59,280 --> 00:28:03,030 or how big the current window is to be able to do different things inside 566 00:28:03,030 --> 00:28:04,600 of our JavaScript code. 567 00:28:04,600 --> 00:28:08,670 So for instance, maybe I wish that there were a way in JavaScript 568 00:28:08,670 --> 00:28:12,210 that I could tell when I was at the bottom of a page 569 00:28:12,210 --> 00:28:15,397 when I had scrolled down all the way to the bottom of the page. 570 00:28:15,397 --> 00:28:18,480 Just in terms of these variables here, and you might not need all of them, 571 00:28:18,480 --> 00:28:22,230 but giving you access to innerWidth, innerHeight, scrollY, 572 00:28:22,230 --> 00:28:24,990 and document body offsetHeight. 573 00:28:24,990 --> 00:28:29,550 What would have to be true about the relationships between these values 574 00:28:29,550 --> 00:28:34,860 for me to know that I had scrolled to the bottom of the page? 575 00:28:34,860 --> 00:28:37,500 Take a look at the image and what scrollY, and innerHeight, 576 00:28:37,500 --> 00:28:38,607 and offsetHeight mean. 577 00:28:38,607 --> 00:28:40,440 And see if you can come up with a way that I 578 00:28:40,440 --> 00:28:42,934 could tell that I was at the bottom of this HTML page-- 579 00:28:42,934 --> 00:28:44,850 that I had scrolled all the way to the bottom. 580 00:28:44,850 --> 00:28:49,296 581 00:28:49,296 --> 00:28:51,766 AUDIENCE: If scrollY equals window.innerHeight. 582 00:28:51,766 --> 00:28:54,100 BRIAN YU: If scrollY equals window.innerHeight. 583 00:28:54,100 --> 00:28:55,850 OK, so that's a good thing so far. 584 00:28:55,850 --> 00:28:58,750 So if scrollY were equal to window innerHeight, that 585 00:28:58,750 --> 00:29:01,000 would mean the amount that I've scrolled down now 586 00:29:01,000 --> 00:29:02,860 is equal to however tall the window is. 587 00:29:02,860 --> 00:29:05,320 So that would mean if my window was originally here, 588 00:29:05,320 --> 00:29:06,460 and I've scrolled down. 589 00:29:06,460 --> 00:29:09,010 I've scrolled down one full window's worth. 590 00:29:09,010 --> 00:29:11,260 But it's possible that there is more information still 591 00:29:11,260 --> 00:29:17,007 below-- that the body is larger than two window's worth of content. 592 00:29:17,007 --> 00:29:19,840 So we'll have to make some slight modifications to be able to detect 593 00:29:19,840 --> 00:29:21,880 when we're at the bottom of the page. 594 00:29:21,880 --> 00:29:22,482 Yeah? 595 00:29:22,482 --> 00:29:32,521 AUDIENCE: It'd be innerHeight plus scrollY equals [INAUDIBLE] 596 00:29:32,521 --> 00:29:33,520 BRIAN YU: Yeah, exactly. 597 00:29:33,520 --> 00:29:39,160 Yeah, so if the innerHeight-- the window.innerHeight plus window.scrollY 598 00:29:39,160 --> 00:29:42,110 were equal to the offsetHeight of the body. 599 00:29:42,110 --> 00:29:44,950 In other words, if the amount that I've scrolled 600 00:29:44,950 --> 00:29:47,830 plus however tall the window is is the same 601 00:29:47,830 --> 00:29:49,960 as the height of this entire document, then 602 00:29:49,960 --> 00:29:51,892 presumably I must have scrolled to the bottom. 603 00:29:51,892 --> 00:29:54,100 So that's an excellent intuition, and that's correct. 604 00:29:54,100 --> 00:29:56,380 That's how we might be able to using these variables, 605 00:29:56,380 --> 00:29:59,200 figure out if I have, in fact, scrolled to the bottom of the page. 606 00:29:59,200 --> 00:30:01,060 And so let's take a look at that in action 607 00:30:01,060 --> 00:30:04,360 and then look at some practical applications of that. 608 00:30:04,360 --> 00:30:10,990 We'll take a look at scroll.html and what scroll.html is going to do 609 00:30:10,990 --> 00:30:14,770 is inside the body of this page, inside of scroll.html, 610 00:30:14,770 --> 00:30:17,030 I just have a whole bunch of paragraphs. 611 00:30:17,030 --> 00:30:21,940 I have paragraph one, two, three, all the way down to paragraph number 100. 612 00:30:21,940 --> 00:30:24,085 So a whole bunch of paragraphs that presumably I 613 00:30:24,085 --> 00:30:25,540 would have to scroll through. 614 00:30:25,540 --> 00:30:29,330 And what I have up inside the JavaScript code-- 615 00:30:29,330 --> 00:30:37,095 if we go up to the top are whenever window.onscroll, whenever I scroll, 616 00:30:37,095 --> 00:30:39,220 the first thing I'm going to do is I'm going to log 617 00:30:39,220 --> 00:30:40,620 some information about these heights. 618 00:30:40,620 --> 00:30:42,620 So if you're using this in your own web browser, 619 00:30:42,620 --> 00:30:45,162 and you look at the console inside of Google Chrome 620 00:30:45,162 --> 00:30:46,870 or whatever web browser you're using, you 621 00:30:46,870 --> 00:30:49,670 can see some of these values, which can help you compare them. 622 00:30:49,670 --> 00:30:55,000 But then here if window.innerHeight plus window.dot.scrollY is greater than 623 00:30:55,000 --> 00:30:58,000 or equal to-- or really just equal to would have been fine-- 624 00:30:58,000 --> 00:31:01,910 the offsetHeight of the body-- that same equation that was just described-- 625 00:31:01,910 --> 00:31:05,200 then let's go ahead and take the body and change its background color 626 00:31:05,200 --> 00:31:09,850 to green and otherwise let the background color be white. 627 00:31:09,850 --> 00:31:12,970 So the idea here is that when I'm scrolling, if I get to the bottom, 628 00:31:12,970 --> 00:31:15,050 I want to change the background color to be green 629 00:31:15,050 --> 00:31:18,220 because I've detected now that I've reached to the bottom of the page. 630 00:31:18,220 --> 00:31:22,030 And so if I go ahead and open up scroll.html, 631 00:31:22,030 --> 00:31:24,340 I see a whole bunch of these individual paragraphs. 632 00:31:24,340 --> 00:31:25,270 And if I scroll-- 633 00:31:25,270 --> 00:31:26,780 right now the background's white-- 634 00:31:26,780 --> 00:31:30,040 if I scroll all the way to the bottom, as soon as the amount 635 00:31:30,040 --> 00:31:31,780 that I've scrolled-- 636 00:31:31,780 --> 00:31:33,640 scrolled plus the height of the window-- 637 00:31:33,640 --> 00:31:36,265 is equal to the entire height of the document-- in other words, 638 00:31:36,265 --> 00:31:37,340 I've reached the bottom-- 639 00:31:37,340 --> 00:31:39,260 the page turns green. 640 00:31:39,260 --> 00:31:41,590 If I scroll up, and now it's white again because I'm 641 00:31:41,590 --> 00:31:43,150 no longer at the bottom of the page. 642 00:31:43,150 --> 00:31:44,200 I scroll back down to the bottom. 643 00:31:44,200 --> 00:31:45,430 Now the page turns green. 644 00:31:45,430 --> 00:31:48,346 And so I'm able to detect now that I've reached the bottom of the page 645 00:31:48,346 --> 00:31:51,610 by using JavaScript and by comparing things about the window and about 646 00:31:51,610 --> 00:31:52,910 the document. 647 00:31:52,910 --> 00:31:54,526 So this is all interesting. 648 00:31:54,526 --> 00:31:55,900 But why is this at all practical? 649 00:31:55,900 --> 00:31:57,970 What might be a use case where it might be 650 00:31:57,970 --> 00:32:01,960 relevant or useful to be able to know when the user has scrolled 651 00:32:01,960 --> 00:32:04,387 to the bottom of the page? 652 00:32:04,387 --> 00:32:05,824 Yeah? 653 00:32:05,824 --> 00:32:08,810 AUDIENCE: Would that load more than a lot of pages have? 654 00:32:08,810 --> 00:32:09,810 BRIAN YU: Yeah, exactly. 655 00:32:09,810 --> 00:32:12,435 A lot of modern web applications now have this either load more 656 00:32:12,435 --> 00:32:14,280 or this automatic loading, where when you 657 00:32:14,280 --> 00:32:16,986 scroll to the bottom of a page of tweets, for instance, 658 00:32:16,986 --> 00:32:19,860 it will automatically load a whole bunch of additional tweets for you 659 00:32:19,860 --> 00:32:21,370 to continue to scroll through. 660 00:32:21,370 --> 00:32:22,680 And so what we're going to do now is take a look 661 00:32:22,680 --> 00:32:25,440 at how we can use JavaScript to build out that kind of idea-- 662 00:32:25,440 --> 00:32:29,910 that idea of infinite scroll, where you can scroll to the bottom of the page 663 00:32:29,910 --> 00:32:32,045 and then load the next set of information. 664 00:32:32,045 --> 00:32:33,420 And this has a lot of advantages. 665 00:32:33,420 --> 00:32:37,107 Why would it be useful to dynamically load new information when 666 00:32:37,107 --> 00:32:38,940 you reach the bottom of the page, as opposed 667 00:32:38,940 --> 00:32:41,370 to just loading it all once at the beginning? 668 00:32:41,370 --> 00:32:42,998 Yeah? 669 00:32:42,998 --> 00:32:46,886 AUDIENCE: Performance [INAUDIBLE] it would be really 670 00:32:46,886 --> 00:32:48,475 slow to load everything all at once. 671 00:32:48,475 --> 00:32:51,350 BRIAN YU: Performance-- certainly, that if there is a lot of content, 672 00:32:51,350 --> 00:32:54,050 and the user might not ever want to look at all that content, 673 00:32:54,050 --> 00:32:55,940 there's is no reason to load it all at once. 674 00:32:55,940 --> 00:32:58,230 And even if they do want to look at all that content, 675 00:32:58,230 --> 00:33:00,271 it's a little bit nicer to load it in increments, 676 00:33:00,271 --> 00:33:02,840 rather than have them wait all this time just to be 677 00:33:02,840 --> 00:33:04,670 able to see the first couple of posts. 678 00:33:04,670 --> 00:33:07,160 And so let's try and implement this infinite scroll now 679 00:33:07,160 --> 00:33:09,950 with this ability and knowledge of how we can detect when 680 00:33:09,950 --> 00:33:12,270 we've reached the bottom of the page. 681 00:33:12,270 --> 00:33:18,620 So I'll go ahead and go into post 0. 682 00:33:18,620 --> 00:33:22,550 And post 0 is just going to be simulating a social media feed, where 683 00:33:22,550 --> 00:33:25,550 I have some number of posts, and really an infinite number of posts that 684 00:33:25,550 --> 00:33:27,500 could continue to infinitely scroll. 685 00:33:27,500 --> 00:33:30,080 And so how is this going to work? 686 00:33:30,080 --> 00:33:32,827 Well, I have this default route that renders index.html, which 687 00:33:32,827 --> 00:33:34,410 we'll take a look at in just a moment. 688 00:33:34,410 --> 00:33:36,290 This is the Flask application. 689 00:33:36,290 --> 00:33:40,220 And now I have this /posts route. 690 00:33:40,220 --> 00:33:43,940 And this /post route is going to be a route that I can access via AJAX 691 00:33:43,940 --> 00:33:48,170 or just by making an HTTP request that will get me some posts. 692 00:33:48,170 --> 00:33:51,080 And in particular, I need to provide as arguments whatever 693 00:33:51,080 --> 00:33:54,680 the start and end of these posts are. 694 00:33:54,680 --> 00:33:58,390 And maybe I want to get posts 1 through 20 for instance. 695 00:33:58,390 --> 00:34:00,110 These ors are just default values in case 696 00:34:00,110 --> 00:34:01,970 I don't specify what the start and end are. 697 00:34:01,970 --> 00:34:05,720 But if I say I want posts 1 through 20, then what I'm going to do 698 00:34:05,720 --> 00:34:07,529 is generate this list of posts. 699 00:34:07,529 --> 00:34:10,070 And the way I'm going to generate this list of posts for now, 700 00:34:10,070 --> 00:34:13,028 since I don't really have a database connected to this web application, 701 00:34:13,028 --> 00:34:15,889 is just call each post number i. 702 00:34:15,889 --> 00:34:18,949 So I'm going to loop through from start number 703 00:34:18,949 --> 00:34:22,239 to end number and just add to this list of posts 704 00:34:22,239 --> 00:34:24,530 a string that says post number 1, post number 2, 705 00:34:24,530 --> 00:34:27,042 post number 3, so on and so forth. 706 00:34:27,042 --> 00:34:30,250 Then you would never actually want to include this in an application but just 707 00:34:30,250 --> 00:34:34,239 to simulate the idea that it might take time to get data from the web server 708 00:34:34,239 --> 00:34:37,170 to query from the database, I'm going to do time.sleep(1), 709 00:34:37,170 --> 00:34:40,570 which just means take a one second pause before doing anything. 710 00:34:40,570 --> 00:34:45,449 And then finally, I'm going to return a JSON response of all of those posts. 711 00:34:45,449 --> 00:34:48,679 So this /post route is going to be how I access new posts. 712 00:34:48,679 --> 00:34:51,480 I'm going to ask for posts1 through 20, presumably. 713 00:34:51,480 --> 00:34:55,870 And then later, ask for 21 through 40 in the next step. 714 00:34:55,870 --> 00:34:58,020 So how does this work? 715 00:34:58,020 --> 00:35:02,640 Let's go ahead and look at post0's index.html, 716 00:35:02,640 --> 00:35:05,610 which is where the interesting stuff is going to happen. 717 00:35:05,610 --> 00:35:07,980 Inside the body of this web page, there's 718 00:35:07,980 --> 00:35:09,690 very little actually in the body. 719 00:35:09,690 --> 00:35:13,110 I have a div, just an HTML element that's going to store the posts. 720 00:35:13,110 --> 00:35:17,610 But right now, just stores id equals post, and that's it. 721 00:35:17,610 --> 00:35:20,700 So nothing actually inside this element. 722 00:35:20,700 --> 00:35:22,950 And so what I'm actually doing-- 723 00:35:22,950 --> 00:35:27,750 well, let's start by looking at this load function. 724 00:35:27,750 --> 00:35:33,150 So inside this load function, I'm going to define a start and end variable, 725 00:35:33,150 --> 00:35:37,260 and they're defined in terms of a counter and quantity. 726 00:35:37,260 --> 00:35:40,260 So I've defined up here let counter equal one. 727 00:35:40,260 --> 00:35:43,094 So the first post that I want to load, that should be post number 1. 728 00:35:43,094 --> 00:35:44,885 And then I have this second variable called 729 00:35:44,885 --> 00:35:47,040 quantity, which is just going to be how many posts 730 00:35:47,040 --> 00:35:48,340 am I going to load at any given time? 731 00:35:48,340 --> 00:35:51,214 So we'll just say, in this case, let's load 20 posts at a time-- load 732 00:35:51,214 --> 00:35:54,870 the first 20, then the next 20, then the 20 after that. 733 00:35:54,870 --> 00:35:57,360 And so I define the start and end value. 734 00:35:57,360 --> 00:35:58,320 I update the counter. 735 00:35:58,320 --> 00:36:00,528 So that the next time when I start loading new posts, 736 00:36:00,528 --> 00:36:03,240 it's going to start from 21, presumably. 737 00:36:03,240 --> 00:36:05,220 And now I'm going to make an HTTP request. 738 00:36:05,220 --> 00:36:08,010 And this is very similar to the HTTP request we made before him. 739 00:36:08,010 --> 00:36:12,360 We're going to make a post request to /post. 740 00:36:12,360 --> 00:36:16,020 And then when we've finished making that request, 741 00:36:16,020 --> 00:36:19,669 we're going to get the data that came back from that response. 742 00:36:19,669 --> 00:36:21,960 And then for each of the items in that data-- remember, 743 00:36:21,960 --> 00:36:26,211 the data is just going to be this long JavaScript array of individual posts. 744 00:36:26,211 --> 00:36:28,960 For each of them, we're going to run this add_post function, which 745 00:36:28,960 --> 00:36:32,150 we'll take a look at it a moment, which is going to add a post to the DOM-- 746 00:36:32,150 --> 00:36:36,202 add a post to the window that the user will actually see. 747 00:36:36,202 --> 00:36:38,160 When we make this request, we need to make sure 748 00:36:38,160 --> 00:36:42,420 that we tell the HTTP request what the start point is, what the end point is, 749 00:36:42,420 --> 00:36:44,160 and then we send the request. 750 00:36:44,160 --> 00:36:48,030 When the request comes back, this add_post is what gets called, 751 00:36:48,030 --> 00:36:50,997 and so add_post is going to be called 20 times. 752 00:36:50,997 --> 00:36:52,830 Every time I try and load 20 new posts, it's 753 00:36:52,830 --> 00:36:56,610 going to be add_post post number 1, add_post post number 2, 754 00:36:56,610 --> 00:36:58,380 so on and so forth. 755 00:36:58,380 --> 00:37:03,180 And to do that, I want to add HTML content to the DOM. 756 00:37:03,180 --> 00:37:05,700 So I'm going to define a new variable, post, 757 00:37:05,700 --> 00:37:11,160 which is going to be the result of creating a new div inside of my page. 758 00:37:11,160 --> 00:37:13,189 I'm going to give it a className of post, 759 00:37:13,189 --> 00:37:16,230 and I'm doing that because up at the top of the page, if you took a look, 760 00:37:16,230 --> 00:37:19,560 you'd find some CSS styling code, where I've given the post a background color, 761 00:37:19,560 --> 00:37:21,600 for instance, just to distinguish it. 762 00:37:21,600 --> 00:37:25,226 And then the innerHTML of the post is content. 763 00:37:25,226 --> 00:37:26,850 Whatever the contents of this post is-- 764 00:37:26,850 --> 00:37:30,930 presumably, it's post 1 or post number 2 or post number 3 or so on and so forth. 765 00:37:30,930 --> 00:37:34,200 And then I'm going to add that post to the DOM so querySelector 766 00:37:34,200 --> 00:37:37,680 posts and go ahead and add to this new post 767 00:37:37,680 --> 00:37:42,550 to my div that contains all of those posts. 768 00:37:42,550 --> 00:37:45,190 So that's ultimately how new posts get added. 769 00:37:45,190 --> 00:37:49,030 Whenever I run the load function, that's going 770 00:37:49,030 --> 00:37:51,130 to make a request for 20 new posts. 771 00:37:51,130 --> 00:37:54,280 For each one of them, I'm going to call the add-post function, which 772 00:37:54,280 --> 00:37:58,720 is going to add a new post to the contents of my HTML page. 773 00:37:58,720 --> 00:38:02,630 So when now does this load function ever get called? 774 00:38:02,630 --> 00:38:05,160 Well, it gets called twice. 775 00:38:05,160 --> 00:38:08,430 It gets called once up here on line 25. 776 00:38:08,430 --> 00:38:09,431 I add an event listener. 777 00:38:09,431 --> 00:38:11,888 When the DOM content is done loading-- in other words, when 778 00:38:11,888 --> 00:38:15,270 the page loads for the first time, go ahead and call that load function. 779 00:38:15,270 --> 00:38:19,230 Load for me the first 20 posts without me having to do anything. 780 00:38:19,230 --> 00:38:24,210 But then also on scroll, whenever I scroll the page, let's check. 781 00:38:24,210 --> 00:38:27,630 If this equation holds-- in other words, if as we talked about before, 782 00:38:27,630 --> 00:38:29,960 I've reached the bottom of the page, then 783 00:38:29,960 --> 00:38:31,460 go ahead and call the load function. 784 00:38:31,460 --> 00:38:35,040 Go ahead and load the next set of 20 posts. 785 00:38:35,040 --> 00:38:37,980 So this load function is what loads us an additional 20 posts, 786 00:38:37,980 --> 00:38:40,680 and this condition is what makes it such that we're only 787 00:38:40,680 --> 00:38:43,410 going to load the next 20 posts if, in fact, we have 788 00:38:43,410 --> 00:38:46,600 reached the bottom of that HTML page. 789 00:38:46,600 --> 00:38:50,140 So how does that ultimately work in practice? 790 00:38:50,140 --> 00:38:56,020 Let's go ahead and go into post zero and run. 791 00:38:56,020 --> 00:38:58,700 And now if I go to this page, what I see immediately 792 00:38:58,700 --> 00:39:01,921 is that I have these individual posts that were all dynamically loaded. 793 00:39:01,921 --> 00:39:04,670 And if you look at the scroll bar, there is not too far to scroll. 794 00:39:04,670 --> 00:39:06,650 And so what you'll notice is that I'll go to the bottom of the page-- 795 00:39:06,650 --> 00:39:08,540 and this will happen fast because it'll be like half a second 796 00:39:08,540 --> 00:39:09,920 before the next one is loaded. 797 00:39:09,920 --> 00:39:13,369 But notice that I get to the bottom post number 20, and that was the end. 798 00:39:13,369 --> 00:39:16,160 Then half a second later, because I reached the bottom of the page, 799 00:39:16,160 --> 00:39:19,347 it queried for the next 20 posts, and now the next 20 posts are here. 800 00:39:19,347 --> 00:39:20,180 I scroll down again. 801 00:39:20,180 --> 00:39:21,140 I'm at 40. 802 00:39:21,140 --> 00:39:24,960 Half a second later, the next 20 posts appear underneath that as well. 803 00:39:24,960 --> 00:39:27,920 And so now I've recreated this idea of this infinite scroll, where 804 00:39:27,920 --> 00:39:30,680 I can continue to scroll to the bottom of the page 805 00:39:30,680 --> 00:39:33,890 and render the next set of posts after that. 806 00:39:33,890 --> 00:39:36,440 Questions about anything we've seen so far? 807 00:39:36,440 --> 00:39:38,560 And how we were able to make that work? 808 00:39:38,560 --> 00:39:41,750 AUDIENCE: The counter, that's a JavaScript variable? 809 00:39:41,750 --> 00:39:44,276 BRIAN YU: Correct, counter is a JavaScript variable. 810 00:39:44,276 --> 00:39:48,630 AUDIENCE: [INAUDIBLE] 811 00:39:48,630 --> 00:39:52,860 BRIAN YU: It was enclosed, so it was inside of the script tag still. 812 00:39:52,860 --> 00:39:55,680 So this whole JavaScript content was all inside the script tag. 813 00:39:55,680 --> 00:39:57,555 And in practice, what you would probably want 814 00:39:57,555 --> 00:40:00,840 to do is move this all out into a separate JavaScript file-- 815 00:40:00,840 --> 00:40:04,230 separate .js file-- just to clean things up so that we don't have JavaScript 816 00:40:04,230 --> 00:40:06,360 and HTML all together. 817 00:40:06,360 --> 00:40:09,840 But because this is inside of the script tag, it will be a JavaScript variable. 818 00:40:09,840 --> 00:40:12,964 In this case, just a global variable that all the functions have access to. 819 00:40:12,964 --> 00:40:15,640 820 00:40:15,640 --> 00:40:19,464 OK, so that was being able to create infinite scroll just 821 00:40:19,464 --> 00:40:21,880 by allowing us to check if we're at the bottom of the page 822 00:40:21,880 --> 00:40:23,590 and then render the next set of posts. 823 00:40:23,590 --> 00:40:27,460 What might be nice now is if we can-- 824 00:40:27,460 --> 00:40:29,560 in addition to creating new posts, maybe we 825 00:40:29,560 --> 00:40:32,170 would want to allow for us to be able to hide posts as well. 826 00:40:32,170 --> 00:40:35,140 If we have a bunch of posts, and ones not interesting to us-- maybe 827 00:40:35,140 --> 00:40:37,330 we don't care about post number 27. 828 00:40:37,330 --> 00:40:42,220 We can hide that post, and then the other posts will just take its place. 829 00:40:42,220 --> 00:40:45,170 So how might we go about doing that? 830 00:40:45,170 --> 00:40:54,270 Let's take a look now at posts one and look at index.html there. 831 00:40:54,270 --> 00:40:57,060 So most of this is exactly the same. 832 00:40:57,060 --> 00:41:00,660 But what will notice is first of all, inside of this add_post function, 833 00:41:00,660 --> 00:41:02,570 we've needed to add a little bit of content. 834 00:41:02,570 --> 00:41:06,470 So when I add a new post, in addition to just creating a new div, 835 00:41:06,470 --> 00:41:10,110 which is going to be storing the contents of this page, 836 00:41:10,110 --> 00:41:13,820 I'm also going to create a new button using document.createElement again. 837 00:41:13,820 --> 00:41:15,560 This is going to be called hide. 838 00:41:15,560 --> 00:41:17,317 I'm going to give it a className of hide. 839 00:41:17,317 --> 00:41:19,400 If you look at the CSS, I've added some properties 840 00:41:19,400 --> 00:41:22,250 to make the Hide button go to the right side of the post just 841 00:41:22,250 --> 00:41:23,600 for aesthetic reasons. 842 00:41:23,600 --> 00:41:26,790 And the contents of that button-- what is that actually going to say? 843 00:41:26,790 --> 00:41:29,910 Well, it's just going to say hide, in this case. 844 00:41:29,910 --> 00:41:33,810 And so I've now added to the post to add this Hide button, 845 00:41:33,810 --> 00:41:38,040 and I've added that Hide button to this div. 846 00:41:38,040 --> 00:41:41,060 What should happen when the Hide button is clicked? 847 00:41:41,060 --> 00:41:44,390 Well, I have this code here that says hide.onclick. 848 00:41:44,390 --> 00:41:46,550 This is the function that I should run. 849 00:41:46,550 --> 00:41:50,090 This refers to whatever this function is being called upon. 850 00:41:50,090 --> 00:41:51,639 In this case, the Hide button. 851 00:41:51,639 --> 00:41:53,930 And in JavaScript, I also have access to this attribute 852 00:41:53,930 --> 00:41:58,430 called parentElement, which gets me whatever HTML element contains 853 00:41:58,430 --> 00:41:59,900 the element in question. 854 00:41:59,900 --> 00:42:06,290 And so if this is the Hide button, then what is this.parentElement? 855 00:42:06,290 --> 00:42:11,394 856 00:42:11,394 --> 00:42:12,330 AUDIENCE: Post div. 857 00:42:12,330 --> 00:42:12,780 BRIAN YU: The post div. 858 00:42:12,780 --> 00:42:13,363 Yeah, exactly. 859 00:42:13,363 --> 00:42:17,010 So I added the Hide button to this post div. 860 00:42:17,010 --> 00:42:21,000 So the Hide button is now the child of the HTML element of the post div. 861 00:42:21,000 --> 00:42:24,960 And so if I have the Hide button, the parentElement of the Hide button 862 00:42:24,960 --> 00:42:26,940 is the post itself. 863 00:42:26,940 --> 00:42:29,100 And so I'm just going to call .remove on that, 864 00:42:29,100 --> 00:42:32,580 which is a built-in function that just takes an HTML element and removes it 865 00:42:32,580 --> 00:42:33,610 altogether. 866 00:42:33,610 --> 00:42:36,900 And so when the Hide button is clicked, that's going to remove the post. 867 00:42:36,900 --> 00:42:44,480 And so with just that small addition, now if I go into posts1 and run that, 868 00:42:44,480 --> 00:42:48,810 now each one of my posts now has a Hide button associated with it. 869 00:42:48,810 --> 00:42:52,310 And if I click Hide next to post 3, for instance, 3 goes away 870 00:42:52,310 --> 00:42:55,760 and now it jumps straight from post 2 to post 4. 871 00:42:55,760 --> 00:42:59,000 And if I scroll down to the bottom 20, I get the auto scroll new, 872 00:42:59,000 --> 00:43:01,220 posts appear, and I can hide those posts as well. 873 00:43:01,220 --> 00:43:04,780 Those go away and the newer posts replace it as well. 874 00:43:04,780 --> 00:43:06,944 Questions about any of this so far? 875 00:43:06,944 --> 00:43:08,405 Yeah? 876 00:43:08,405 --> 00:43:13,275 AUDIENCE: Just go back to code and was just wondering about-- 877 00:43:13,275 --> 00:43:17,658 where you have those constants defined, but you're citing-- 878 00:43:17,658 --> 00:43:20,580 879 00:43:20,580 --> 00:43:24,039 I guess I'm just confused about constants [INAUDIBLE].. 880 00:43:24,039 --> 00:43:25,080 BRIAN YU: Great question. 881 00:43:25,080 --> 00:43:26,642 So the question is about these const. 882 00:43:26,642 --> 00:43:28,670 I have const post and const hide. 883 00:43:28,670 --> 00:43:30,920 We learned that constant variables can't be changed, 884 00:43:30,920 --> 00:43:33,860 yet it seems like I'm calling add posts multiple times-- time and time again 885 00:43:33,860 --> 00:43:36,151 on the first post, second, third, or so on and so forth 886 00:43:36,151 --> 00:43:39,170 where these Post and Hide buttons are referring to different things. 887 00:43:39,170 --> 00:43:40,370 So why is that allowed? 888 00:43:40,370 --> 00:43:42,750 And the answer has to do with variable scoping. 889 00:43:42,750 --> 00:43:48,060 So because this variable exists only inside of this add-post function, 890 00:43:48,060 --> 00:43:52,490 then the next time the add-post function is called, when I say const post, 891 00:43:52,490 --> 00:43:55,160 this is an entirely new variable called post, 892 00:43:55,160 --> 00:43:57,320 and it has nothing to do with the original one. 893 00:43:57,320 --> 00:44:00,800 So const post would mean that inside of this same scope, if I tried 894 00:44:00,800 --> 00:44:03,560 to change post equals something else down here, 895 00:44:03,560 --> 00:44:07,280 later in the function, that wouldn't be allowed because then post would refer 896 00:44:07,280 --> 00:44:10,400 to this same variable post that I said wasn't going to change because I 897 00:44:10,400 --> 00:44:12,150 called that a constant variable. 898 00:44:12,150 --> 00:44:17,040 But if inside of the entire body of this function, post will not change, 899 00:44:17,040 --> 00:44:19,160 then it's OK for it to be a constant variable 900 00:44:19,160 --> 00:44:24,290 because the post variable is born when I first define it. 901 00:44:24,290 --> 00:44:26,940 And the post variable dies at the end of the function. 902 00:44:26,940 --> 00:44:30,440 So when add_post is done being run, the post variable goes away entirely. 903 00:44:30,440 --> 00:44:33,980 And the next time I run line 67 here, this is a fresh variable, 904 00:44:33,980 --> 00:44:37,590 and so it is OK to let that still be constant. 905 00:44:37,590 --> 00:44:40,530 AUDIENCE: I understood that [INAUDIBLE] 906 00:44:40,530 --> 00:44:42,246 BRIAN YU: Yeah, no problem. 907 00:44:42,246 --> 00:44:45,697 AUDIENCE: But I was wondering about-- so you're setting-- 908 00:44:45,697 --> 00:44:49,641 I don't know what you would call that-- like a number of-- 909 00:44:49,641 --> 00:44:52,599 so even though it's a constant, you're able to assign 910 00:44:52,599 --> 00:44:55,102 values to whatever that dot is. 911 00:44:55,102 --> 00:44:56,310 BRIAN YU: Oh, great question. 912 00:44:56,310 --> 00:44:59,490 So even though it's a constant o line 68 and 69, 913 00:44:59,490 --> 00:45:03,570 I'm still able to modify the className and the innerHTML of the post. 914 00:45:03,570 --> 00:45:04,620 Yes, you can. 915 00:45:04,620 --> 00:45:07,320 And so it's a constant variable in the sense 916 00:45:07,320 --> 00:45:09,750 that it's always going to refer to the same thing. 917 00:45:09,750 --> 00:45:13,960 It's always referring to whatever the result of creating the element div is. 918 00:45:13,960 --> 00:45:17,137 So I've created this new div element and post will always 919 00:45:17,137 --> 00:45:18,220 refer to that development. 920 00:45:18,220 --> 00:45:21,801 I could never make post refer to some other div element, for example. 921 00:45:21,801 --> 00:45:23,550 But if it's referring to that div element, 922 00:45:23,550 --> 00:45:27,180 I can still change the properties of this div element 923 00:45:27,180 --> 00:45:29,889 by assigning the className or innerHTML attribute of it. 924 00:45:29,889 --> 00:45:31,680 So that is something you are allowed to do. 925 00:45:31,680 --> 00:45:33,090 You just can't change. 926 00:45:33,090 --> 00:45:37,090 I could never have a line that was like post equals something else entirely. 927 00:45:37,090 --> 00:45:38,541 Yeah, great questions. 928 00:45:38,541 --> 00:45:40,784 AUDIENCE: Is it like a pointer, the div [INAUDIBLE]?? 929 00:45:40,784 --> 00:45:43,950 BRIAN YU: Yeah, you can think of it as analogous to a pointer in that sense. 930 00:45:43,950 --> 00:45:45,519 That it's pointing to the div object. 931 00:45:45,519 --> 00:45:47,310 It will always point there, but I can still 932 00:45:47,310 --> 00:45:50,800 change the information that's actually within that div object that can modify 933 00:45:50,800 --> 00:45:52,470 its innerHTML and so on and so forth. 934 00:45:52,470 --> 00:45:55,980 935 00:45:55,980 --> 00:45:59,370 OK, so what we've maybe noticed at this point 936 00:45:59,370 --> 00:46:01,410 is that as I started to use JavaScript to be 937 00:46:01,410 --> 00:46:05,520 able to build a more complicated user interfaces, to add things to the DOM 938 00:46:05,520 --> 00:46:09,090 later, this code in general is just starting to get a little bit messy 939 00:46:09,090 --> 00:46:12,660 that I have to create a div and assign its className 940 00:46:12,660 --> 00:46:15,330 to be post assign its innerHTML to be the content. 941 00:46:15,330 --> 00:46:17,220 Really what I would like to be able to do 942 00:46:17,220 --> 00:46:19,770 is just write the HTML for all of this code. 943 00:46:19,770 --> 00:46:24,510 Write a div and set class equals post and inside of it have the contents. 944 00:46:24,510 --> 00:46:26,490 But of course, I am not currently able to do 945 00:46:26,490 --> 00:46:30,647 that because I don't in advance know the exact HTML 946 00:46:30,647 --> 00:46:31,980 that I want to put into the DOM. 947 00:46:31,980 --> 00:46:34,710 I don't necessarily know what the contents of all of the posts 948 00:46:34,710 --> 00:46:36,070 are going to be. 949 00:46:36,070 --> 00:46:39,630 And so this is where we're going to introduce a new idea of JavaScript 950 00:46:39,630 --> 00:46:42,630 templating, where we can build templates in JavaScript that 951 00:46:42,630 --> 00:46:46,380 allow us to really write exactly what HTML that we want 952 00:46:46,380 --> 00:46:50,490 and maybe substitute in different aspects of those templates 953 00:46:50,490 --> 00:46:52,560 in order to customize them to our liking. 954 00:46:52,560 --> 00:46:56,140 We've already seen this a little bit in the context of the backtick symbols-- 955 00:46:56,140 --> 00:47:01,680 these ES6 template literals, where, for instance, in some 956 00:47:01,680 --> 00:47:04,500 of our previous examples we were able to plug in 957 00:47:04,500 --> 00:47:07,650 into URL, for example, like dollar sign and then in curly braces, 958 00:47:07,650 --> 00:47:09,150 plug in something here. 959 00:47:09,150 --> 00:47:11,410 We're going to be building on those same ideas. 960 00:47:11,410 --> 00:47:13,540 But this time, taking them to the next level. 961 00:47:13,540 --> 00:47:15,674 And so there are all sorts of JavaScript libraries 962 00:47:15,674 --> 00:47:17,340 that are designed for this very purpose. 963 00:47:17,340 --> 00:47:21,000 I'm trying to make it easy to create templates in JavaScript that you 964 00:47:21,000 --> 00:47:24,510 can then allow to yourself to build HTML elements that you can then 965 00:47:24,510 --> 00:47:26,220 insert into the DOM. 966 00:47:26,220 --> 00:47:29,940 Some popular ones include Mustache and Underscore and Lodash and Handlebars 967 00:47:29,940 --> 00:47:31,227 and all sorts of other ones. 968 00:47:31,227 --> 00:47:33,810 For this class, we're just going to take a look at Handlebars, 969 00:47:33,810 --> 00:47:36,390 which is one such example of these templating libraries 970 00:47:36,390 --> 00:47:38,790 it's by no means the only one, and different ones 971 00:47:38,790 --> 00:47:40,932 have their different advantages and costs. 972 00:47:40,932 --> 00:47:43,890 But once you've seen one, you'll get the general sense for what they do 973 00:47:43,890 --> 00:47:48,230 and how they work, and the other ones become very easy to pick up after that. 974 00:47:48,230 --> 00:47:50,160 And so what we're going to be building now 975 00:47:50,160 --> 00:47:53,160 is a set of applications that allow us to roll dice. 976 00:47:53,160 --> 00:47:56,354 Maybe we want a dice simulator program that rolls dice for us, 977 00:47:56,354 --> 00:47:58,020 and that's what we're going to be doing. 978 00:47:58,020 --> 00:48:04,150 So let's take a look at the example of dice zero. 979 00:48:04,150 --> 00:48:06,150 And I'll go ahead and run this application first 980 00:48:06,150 --> 00:48:08,316 to show you how it works, and then we'll take a look 981 00:48:08,316 --> 00:48:10,200 at the code that actually makes it work. 982 00:48:10,200 --> 00:48:13,710 So if I refresh this page-- 983 00:48:13,710 --> 00:48:14,240 oh, sorry. 984 00:48:14,240 --> 00:48:15,573 This is not a Flask application. 985 00:48:15,573 --> 00:48:17,460 I'm just going to open up dice.html. 986 00:48:17,460 --> 00:48:19,860 So this is just an HTML page-- no Flask involved. 987 00:48:19,860 --> 00:48:21,810 Just HTML and JavaScript. 988 00:48:21,810 --> 00:48:24,580 And what I have on this page is a Roll button. 989 00:48:24,580 --> 00:48:26,839 And when I click Roll, it says you rolled a 2. 990 00:48:26,839 --> 00:48:27,630 I click Roll again. 991 00:48:27,630 --> 00:48:28,922 You rolled a 2. 992 00:48:28,922 --> 00:48:29,880 I rolled a bunch of 2s. 993 00:48:29,880 --> 00:48:32,560 But now it shows that I'm going to keep rolling different dice, 994 00:48:32,560 --> 00:48:34,601 and I'm going to get a different value each time. 995 00:48:34,601 --> 00:48:37,570 And each time it's going to add that to the DOM. 996 00:48:37,570 --> 00:48:41,490 And so we'll take a look at how we could build something like this using 997 00:48:41,490 --> 00:48:43,280 a templating library like Handlebars. 998 00:48:43,280 --> 00:48:45,030 And then look at how we can use Handlebars 999 00:48:45,030 --> 00:48:48,850 to extend this to make it even more powerful and even more functional. 1000 00:48:48,850 --> 00:48:54,420 So let's take a look at dice.html. 1001 00:48:54,420 --> 00:48:59,239 And inside the body of this HTML page, I have a button called Roll. 1002 00:48:59,239 --> 00:49:02,280 And then this unordered list of rolls, which is going to start out empty. 1003 00:49:02,280 --> 00:49:03,540 So nothing too crazy so far. 1004 00:49:03,540 --> 00:49:05,831 A button and then an unordered list that eventually I'm 1005 00:49:05,831 --> 00:49:07,650 going to be adding things to. 1006 00:49:07,650 --> 00:49:11,400 So what needs to go inside of the JavaScript? 1007 00:49:11,400 --> 00:49:13,630 Well, here is the code. 1008 00:49:13,630 --> 00:49:17,160 The first thing that I'm going to do is define a JavaScript template. 1009 00:49:17,160 --> 00:49:19,530 This is going to be the Handlebars template 1010 00:49:19,530 --> 00:49:21,889 that I'm going to create that I'm going to use 1011 00:49:21,889 --> 00:49:23,430 whenever I want to create a new role. 1012 00:49:23,430 --> 00:49:26,390 This is the template for what should be added to the DOM 1013 00:49:26,390 --> 00:49:27,960 anytime I roll the dice? 1014 00:49:27,960 --> 00:49:30,730 So in this case, I'm going to say Kant's template equals 1015 00:49:30,730 --> 00:49:35,280 the handlebars.compile is just how you compile or create a brand new template. 1016 00:49:35,280 --> 00:49:38,344 And this template resembles a lot like the Jinja type 1017 00:49:38,344 --> 00:49:40,510 templates that we used when we were working in Flask 1018 00:49:40,510 --> 00:49:45,210 and think of it as sort of the client-side analog to what the Flask 1019 00:49:45,210 --> 00:49:47,740 templates were like on the server. 1020 00:49:47,740 --> 00:49:51,450 And this template is just going to be very simply, li-- a list item. 1021 00:49:51,450 --> 00:49:54,030 You rolled a and then these double curly braces. 1022 00:49:54,030 --> 00:49:56,326 Just like in Jinja, they meant plug in a value here. 1023 00:49:56,326 --> 00:49:57,950 They mean the same thing in Handlebars. 1024 00:49:57,950 --> 00:49:59,440 Plug any value here. 1025 00:49:59,440 --> 00:50:03,570 We're going to plug in a value and then close the list item /li. 1026 00:50:03,570 --> 00:50:06,780 And so that is this template that we've now created using Handlebars, 1027 00:50:06,780 --> 00:50:08,280 and we'll use that, eventually. 1028 00:50:08,280 --> 00:50:09,370 When do we use it? 1029 00:50:09,370 --> 00:50:11,860 Well, whenever the Roll button is clicked-- 1030 00:50:11,860 --> 00:50:14,610 so we select the Roll button-- the thing that id roll. 1031 00:50:14,610 --> 00:50:17,340 When it's clicked, run this code. 1032 00:50:17,340 --> 00:50:22,180 And so here is roll, which is equal to this equation here. 1033 00:50:22,180 --> 00:50:26,130 And so math.random is a built-in JavaScript function that gives me 1034 00:50:26,130 --> 00:50:28,410 a random number between 0 and 1. 1035 00:50:28,410 --> 00:50:31,800 And given a random number between 0 and 1, that's not actually what I want. 1036 00:50:31,800 --> 00:50:35,770 I want an integer between 1 and 6 inclusive. 1037 00:50:35,770 --> 00:50:39,220 And so I'm first going to take this random number and multiply it by 6. 1038 00:50:39,220 --> 00:50:46,140 Now I have a random real number between 0 and 6-- 1039 00:50:46,140 --> 00:50:48,105 0 and 6 but not including 6. 1040 00:50:48,105 --> 00:50:51,815 0 up to 5.99999, presumably. 1041 00:50:51,815 --> 00:50:53,440 But that's still not quite what I want. 1042 00:50:53,440 --> 00:50:54,790 So I'm going to add 1 to it. 1043 00:50:54,790 --> 00:50:58,850 Now I've got a random number between 1 and 6.99999. 1044 00:50:58,850 --> 00:51:01,190 And by taking the floor of that-- math.floor 1045 00:51:01,190 --> 00:51:03,170 is another built-in function in JavaScript. 1046 00:51:03,170 --> 00:51:05,927 That's going to give me one, two, three, four, five, or six. 1047 00:51:05,927 --> 00:51:07,760 And so this is a common paradigm that you'll 1048 00:51:07,760 --> 00:51:11,690 see whenever you want to generate a random number in some range, 1049 00:51:11,690 --> 00:51:13,720 JavaScript built-in only lets me generate 1050 00:51:13,720 --> 00:51:15,927 a random real number between 0 and 1. 1051 00:51:15,927 --> 00:51:18,260 But by doing some math to it, by multiplying, by adding, 1052 00:51:18,260 --> 00:51:22,400 by taking the floor, I can convert that to a random number in whatever range 1053 00:51:22,400 --> 00:51:23,450 I happen to want. 1054 00:51:23,450 --> 00:51:25,455 And so Roll will give me some random roll. 1055 00:51:25,455 --> 00:51:28,580 And now I need to take that roll value, one, two, three, four, five, or six 1056 00:51:28,580 --> 00:51:30,380 and actually add it to the DOM. 1057 00:51:30,380 --> 00:51:33,830 And so what is the content of what I'm going to add to the DOM? 1058 00:51:33,830 --> 00:51:35,880 Well, I'm going to run this template. 1059 00:51:35,880 --> 00:51:38,090 This template you can think of now as a function that 1060 00:51:38,090 --> 00:51:42,920 is going to take arguments that define what to plug into this template. 1061 00:51:42,920 --> 00:51:46,590 And then give back to me the HTML content that I actually care about. 1062 00:51:46,590 --> 00:51:48,470 So I'm going to run this template, passing 1063 00:51:48,470 --> 00:51:50,930 in this JavaScript object that says, here is 1064 00:51:50,930 --> 00:51:52,730 the value that I want you to plug in-- 1065 00:51:52,730 --> 00:51:55,760 where this value matches up with this value here. 1066 00:51:55,760 --> 00:51:57,830 And the value is roll. 1067 00:51:57,830 --> 00:51:59,960 Whatever this variable roll was, the result 1068 00:51:59,960 --> 00:52:04,110 of doing the math.random and then the mathematical manipulation. 1069 00:52:04,110 --> 00:52:10,010 And so that will give back to me li you rolled a 2 /li, for example. 1070 00:52:10,010 --> 00:52:12,020 And I'm going to take that content and just 1071 00:52:12,020 --> 00:52:17,090 add it to the HTML of my unordered list of rolls. 1072 00:52:17,090 --> 00:52:22,430 So the result of that is that I can now click the button that 1073 00:52:22,430 --> 00:52:23,840 generates the new template. 1074 00:52:23,840 --> 00:52:27,380 And notice this value 4-- or whatever the value of the roll was-- 1075 00:52:27,380 --> 00:52:33,480 gets plugged into this template of list item you rolled a plug in a value here. 1076 00:52:33,480 --> 00:52:38,070 So this is just a very simple example of an HTML template. 1077 00:52:38,070 --> 00:52:41,210 And if I wanted to make this application more interesting, more dynamic, 1078 00:52:41,210 --> 00:52:46,240 maybe instead of just plugging in a text value of just roll-- 1079 00:52:46,240 --> 00:52:47,990 you rolled a one, two, three, maybe I will 1080 00:52:47,990 --> 00:52:50,840 care about putting in an actual image of dice. 1081 00:52:50,840 --> 00:52:56,730 And so I have an inside of dice1, a whole bunch of images. 1082 00:52:56,730 --> 00:53:02,180 And so I have an image for the one, two, three, four, five, and six. 1083 00:53:02,180 --> 00:53:04,280 These are just PNG images that I happened 1084 00:53:04,280 --> 00:53:07,310 have stored in the same directory as this HTML file 1085 00:53:07,310 --> 00:53:08,480 that I'm going to work with. 1086 00:53:08,480 --> 00:53:14,000 And using that, I'm going to try to actually plug in the image of the dice, 1087 00:53:14,000 --> 00:53:16,360 instead of just the text value. 1088 00:53:16,360 --> 00:53:20,840 And so let's go ahead and look at dice1 dice.html. 1089 00:53:20,840 --> 00:53:22,910 This is all going to be almost identical. 1090 00:53:22,910 --> 00:53:26,690 The only difference is in what the template is, 1091 00:53:26,690 --> 00:53:28,730 what it is that I'm compiling. 1092 00:53:28,730 --> 00:53:30,920 And I'm going to say you rolled. 1093 00:53:30,920 --> 00:53:35,900 And then rather than just plug in a value here, what I'm going to plug in 1094 00:53:35,900 --> 00:53:38,420 is an image. 1095 00:53:38,420 --> 00:53:40,244 So image source equals. 1096 00:53:40,244 --> 00:53:42,660 And the source, I usually use enclosed in quotation marks, 1097 00:53:42,660 --> 00:53:46,430 but I have to be careful because this whole JavaScript template is itself 1098 00:53:46,430 --> 00:53:48,030 already in quotation marks. 1099 00:53:48,030 --> 00:53:50,090 I need to escape these quotation marks to make 1100 00:53:50,090 --> 00:53:53,150 sure JavaScript knows treat this as an actual quotation mark 1101 00:53:53,150 --> 00:53:54,980 and not the end of the string. 1102 00:53:54,980 --> 00:53:58,050 And so I say slash, quotation mark, where is the image stored? 1103 00:53:58,050 --> 00:54:03,690 Well, it's image 1.PNG or 2.PNG or whatever the image is. 1104 00:54:03,690 --> 00:54:07,310 So I'm going to plug in the value here now in the file name of the image 1105 00:54:07,310 --> 00:54:11,130 that I want to display and then close that image tag. 1106 00:54:11,130 --> 00:54:14,480 And so the result of this is hopefully going to be that I say you rolled. 1107 00:54:14,480 --> 00:54:17,060 And then it's going to actually plug in an image there. 1108 00:54:17,060 --> 00:54:23,280 And so now if I go ahead and open dice.html, if I click Roll, 1109 00:54:23,280 --> 00:54:24,510 you rolled a five. 1110 00:54:24,510 --> 00:54:25,260 You rolled a two. 1111 00:54:25,260 --> 00:54:26,010 You rolled a six. 1112 00:54:26,010 --> 00:54:29,790 And so now I get the image actually placed in there as well. 1113 00:54:29,790 --> 00:54:34,440 But this still isn't perfect because this is still a little bit 1114 00:54:34,440 --> 00:54:38,760 messy that all of the contents of the JavaScript template 1115 00:54:38,760 --> 00:54:41,830 that I want to insert here has to be enclosed inside of this string. 1116 00:54:41,830 --> 00:54:45,670 And we're starting to notice this string is beginning to get pretty long. 1117 00:54:45,670 --> 00:54:49,237 And as a result, it's a little bit inconvenient. 1118 00:54:49,237 --> 00:54:50,820 I have to worry about it getting long. 1119 00:54:50,820 --> 00:54:53,153 I have to worry about these quotation marks or whatever. 1120 00:54:53,153 --> 00:54:56,940 I would really like to do is just write pure HTML 1121 00:54:56,940 --> 00:54:59,730 and then figure out a way to get Handlebars to compile that. 1122 00:54:59,730 --> 00:55:01,450 How do we make that work? 1123 00:55:01,450 --> 00:55:04,310 Well, let's take a look at dice2 now. 1124 00:55:04,310 --> 00:55:07,180 1125 00:55:07,180 --> 00:55:12,790 So what I'm going to do here is, first and foremost, before any 1126 00:55:12,790 --> 00:55:17,440 of my actual JavaScript, I have this additional script tag. 1127 00:55:17,440 --> 00:55:20,030 And this script tag has an ID called result, 1128 00:55:20,030 --> 00:55:22,870 it's going to represent the result of performing a die roll. 1129 00:55:22,870 --> 00:55:24,310 And it has a special type. 1130 00:55:24,310 --> 00:55:26,420 This is just a type that's defined by Handlebars, 1131 00:55:26,420 --> 00:55:28,150 and Handlebars knows how to look for it. 1132 00:55:28,150 --> 00:55:31,060 It's typed as tech/x-handlebars-template. 1133 00:55:31,060 --> 00:55:33,370 So inside of the script tags that are going 1134 00:55:33,370 --> 00:55:37,960 to be HTML code that is going to represent the handlebars 1135 00:55:37,960 --> 00:55:41,890 template that I want to create here. 1136 00:55:41,890 --> 00:55:43,620 And so in particular, what do I have? 1137 00:55:43,620 --> 00:55:47,260 I have a list item, and it says you rolled, 1138 00:55:47,260 --> 00:55:51,170 and then it has this image, which has an alt value and a title value. 1139 00:55:51,170 --> 00:55:53,110 These are so that if I hover over the image, 1140 00:55:53,110 --> 00:55:56,170 then it will show me the text of what number I rolled. 1141 00:55:56,170 --> 00:56:01,630 And this is also useful for people that are looking at a browser that 1142 00:56:01,630 --> 00:56:03,250 doesn't support images, for instance. 1143 00:56:03,250 --> 00:56:06,550 They'll be able to see the alternate value text there as well. 1144 00:56:06,550 --> 00:56:12,220 And the source of the image is an image and then plug in a value here, .PNG. 1145 00:56:12,220 --> 00:56:16,360 Notice that I'm still able to use this Handlebars template syntax of plug 1146 00:56:16,360 --> 00:56:19,840 in the value here into the HTML, even though I'm not really 1147 00:56:19,840 --> 00:56:22,000 inside of a Handlebars.compile. 1148 00:56:22,000 --> 00:56:24,440 We'll see why we're allowed to do that in just a moment. 1149 00:56:24,440 --> 00:56:27,064 But the advantage here is that I'm able to literally just write 1150 00:56:27,064 --> 00:56:29,980 the HTML that I care about, plugging in values whenever 1151 00:56:29,980 --> 00:56:34,185 I need to using the double curly braces without needing to worry about escaping 1152 00:56:34,185 --> 00:56:37,060 the quotation marks, without needing to worry about making everything 1153 00:56:37,060 --> 00:56:38,710 in one long string. 1154 00:56:38,710 --> 00:56:41,490 I've just written here inside of these script tags 1155 00:56:41,490 --> 00:56:46,610 the HTML code that eventually I'm going to want to add to the web page. 1156 00:56:46,610 --> 00:56:48,850 So now what happens here? 1157 00:56:48,850 --> 00:56:53,920 Well, rather than handlebar.compiling a big long string, 1158 00:56:53,920 --> 00:56:56,140 representing the entirety of what I want to compile 1159 00:56:56,140 --> 00:57:02,350 into the template, what I can say is document.querySelector pound result 1160 00:57:02,350 --> 00:57:03,860 innerHTML. 1161 00:57:03,860 --> 00:57:06,080 In other words, get the thing with id result, 1162 00:57:06,080 --> 00:57:08,470 which is that script block up above. 1163 00:57:08,470 --> 00:57:09,790 Get the innerHTML. 1164 00:57:09,790 --> 00:57:10,490 event. 1165 00:57:10,490 --> 00:57:12,340 And that's the thing you should compile. 1166 00:57:12,340 --> 00:57:16,030 In other words, I'm saying get the contents of this script tag here. 1167 00:57:16,030 --> 00:57:18,140 This is the template that I want to use. 1168 00:57:18,140 --> 00:57:20,410 So go ahead and use that as the template. 1169 00:57:20,410 --> 00:57:24,340 And now when I call in the template, I can plug in individual values 1170 00:57:24,340 --> 00:57:26,380 there as well. 1171 00:57:26,380 --> 00:57:31,960 So if I go into dice 2 and open that up. 1172 00:57:31,960 --> 00:57:34,230 Now when I roll, I see you rolled a six-- 1173 00:57:34,230 --> 00:57:35,490 different things I can roll. 1174 00:57:35,490 --> 00:57:38,640 And hovering over the image, I get this alternative text as well. 1175 00:57:38,640 --> 00:57:44,030 I hover over the image, and a six shows up or a four or a six or four 1176 00:57:44,030 --> 00:57:48,300 because that's the title text of the image that I've created. 1177 00:57:48,300 --> 00:57:54,490 And that was all just substituted in via the script tag. 1178 00:57:54,490 --> 00:57:57,400 And so using this, I can begin to factor out some of the templates, 1179 00:57:57,400 --> 00:58:00,940 put them into different script blocks, and that makes it a little bit easier. 1180 00:58:00,940 --> 00:58:02,484 Yeah, question? 1181 00:58:02,484 --> 00:58:06,300 AUDIENCE: Yeah, the assignment, you used [INAUDIBLE]---- 1182 00:58:06,300 --> 00:58:08,208 is it part of the document? 1183 00:58:08,208 --> 00:58:09,700 [INAUDIBLE] 1184 00:58:09,700 --> 00:58:10,700 BRIAN YU: Good question. 1185 00:58:10,700 --> 00:58:12,680 Why am I allowed to use document.querySelector? 1186 00:58:12,680 --> 00:58:17,580 Document refers to really everything in the entire contents of the HTML page. 1187 00:58:17,580 --> 00:58:20,604 So it includes things that are outside of just the body section. 1188 00:58:20,604 --> 00:58:22,520 So even though the script is outside the body, 1189 00:58:22,520 --> 00:58:24,690 I can still do the querySelector with the document. 1190 00:58:24,690 --> 00:58:31,060 AUDIENCE: OK, [INAUDIBLE] been doing this this way or doing anything like 1191 00:58:31,060 --> 00:58:32,059 [INAUDIBLE] 1192 00:58:32,059 --> 00:58:33,100 BRIAN YU: Great question. 1193 00:58:33,100 --> 00:58:35,349 So what's the difference between doing things this way 1194 00:58:35,349 --> 00:58:37,465 and doing things with Jinja as we saw before? 1195 00:58:37,465 --> 00:58:40,090 So Jinja was that templating language we used with Flask, where 1196 00:58:40,090 --> 00:58:43,930 we would likewise use the double curly braces to say plug in a value here. 1197 00:58:43,930 --> 00:58:47,170 The difference is the Jijja templates are generated on the server. 1198 00:58:47,170 --> 00:58:49,100 So we needed a Flask server running. 1199 00:58:49,100 --> 00:58:51,850 And when I requested a page from the Flask server, 1200 00:58:51,850 --> 00:58:54,910 Flask could use a Jinja template to plug things in it 1201 00:58:54,910 --> 00:58:57,040 and then hand that back to the client. 1202 00:58:57,040 --> 00:59:00,850 What we have now is templates that are being rendered and generated 1203 00:59:00,850 --> 00:59:02,060 on the client computer. 1204 00:59:02,060 --> 00:59:04,330 So there is a performance benefit there because we 1205 00:59:04,330 --> 00:59:06,820 don't need to ask the server to render the new template 1206 00:59:06,820 --> 00:59:08,050 and then send it back to us. 1207 00:59:08,050 --> 00:59:10,269 We can do it all just in the client's web browser. 1208 00:59:10,269 --> 00:59:12,310 And in an example like this, where there actually 1209 00:59:12,310 --> 00:59:17,380 is no Flask server involved at all, it's just this HTML page. 1210 00:59:17,380 --> 00:59:19,811 That allows me to do the same sort of templating thing 1211 00:59:19,811 --> 00:59:22,060 whereas I couldn't use Jinja here because I don't have 1212 00:59:22,060 --> 00:59:23,890 a Flask server that's running at all. 1213 00:59:23,890 --> 00:59:28,750 I'm just looking at an HTML page but good questions. 1214 00:59:28,750 --> 00:59:31,360 OK, so that was nice. 1215 00:59:31,360 --> 00:59:33,910 But what might be helpful now is just like in Jinja, we 1216 00:59:33,910 --> 00:59:37,360 saw that we could not only plug in values, but we could loop overvalues. 1217 00:59:37,360 --> 00:59:40,180 We could say if I want to print everything out in a list, 1218 00:59:40,180 --> 00:59:42,370 I can iterate over all the elements in the list 1219 00:59:42,370 --> 00:59:44,750 and apply some sort of templating logic to it. 1220 00:59:44,750 --> 00:59:48,700 Handlebar supports the exact same thing, as do many other JavaScript templating 1221 00:59:48,700 --> 00:59:49,630 libraries. 1222 00:59:49,630 --> 00:59:54,670 And so maybe what I want to do now is let's take a look at dice three first. 1223 00:59:54,670 --> 00:59:58,780 What I want to support is the idea that maybe instead of rolling ones, 1224 00:59:58,780 --> 01:00:01,740 I want to be able to roll eight times, for example. 1225 01:00:01,740 --> 01:00:03,999 And I want to be able to click roll on those 1226 01:00:03,999 --> 01:00:06,790 in order to get eight different rolls, or I want to be able to type 1227 01:00:06,790 --> 01:00:10,750 in five to get five different rolls and specify any arbitrary number of rolls 1228 01:00:10,750 --> 01:00:13,360 that I want and get those generated on the page. 1229 01:00:13,360 --> 01:00:14,450 How is that going to work? 1230 01:00:14,450 --> 01:00:17,500 And notice here in addition to getting all the rolls, that are just 1231 01:00:17,500 --> 01:00:19,290 laid out one after the other, we also have 1232 01:00:19,290 --> 01:00:21,040 a nice total at the end that just tells me 1233 01:00:21,040 --> 01:00:23,290 the total count of all of those dice. 1234 01:00:23,290 --> 01:00:26,380 How might we go about doing something like that? 1235 01:00:26,380 --> 01:00:30,060 Well, let's now just take a look at dice three, 1236 01:00:30,060 --> 01:00:32,340 which is going to be fundamentally very similar 1237 01:00:32,340 --> 01:00:35,190 but let's take a look at what's different about this template. 1238 01:00:35,190 --> 01:00:37,450 So inside of the template-- 1239 01:00:37,450 --> 01:00:38,910 it's just called result again-- 1240 01:00:38,910 --> 01:00:43,035 we have you rolled, and then we have the special syntax pound each. 1241 01:00:43,035 --> 01:00:46,320 This pound is what in Handlebars is called a block helper. 1242 01:00:46,320 --> 01:00:49,410 There are a whole bunch of built-in block helpers like pound each 1243 01:00:49,410 --> 01:00:50,130 that does a loop. 1244 01:00:50,130 --> 01:00:52,260 There's a pound if for doing conditions, just 1245 01:00:52,260 --> 01:00:54,030 like we could do conditions in Jinja. 1246 01:00:54,030 --> 01:00:56,280 And if you weren't satisfied with the built-in block helpers that 1247 01:00:56,280 --> 01:00:58,080 are given to you by Handlebars, Handlebars 1248 01:00:58,080 --> 01:01:01,140 makes it very easy to let you create your own helpers as well 1249 01:01:01,140 --> 01:01:02,980 and use them inside your code. 1250 01:01:02,980 --> 01:01:05,820 But for now each is all we need to, and each is going to loop 1251 01:01:05,820 --> 01:01:08,910 over a variable called values. 1252 01:01:08,910 --> 01:01:12,270 And each one of those values Handlebars calls this. 1253 01:01:12,270 --> 01:01:14,910 So for each one of these individual values, 1254 01:01:14,910 --> 01:01:20,790 we're going to include an image that is going to be that number.png. 1255 01:01:20,790 --> 01:01:23,670 And then at the end, we have total, and then we're 1256 01:01:23,670 --> 01:01:25,680 plugging in a value called total. 1257 01:01:25,680 --> 01:01:28,660 So in order to make this template work, we need two things. 1258 01:01:28,660 --> 01:01:31,030 We need to pass to this template a total, which 1259 01:01:31,030 --> 01:01:33,570 is some number representing the total number of rolls. 1260 01:01:33,570 --> 01:01:36,540 And we also need to pass at a JavaScript array called 1261 01:01:36,540 --> 01:01:42,780 values, where each item in that array is the number of whatever the actual roll 1262 01:01:42,780 --> 01:01:43,680 was. 1263 01:01:43,680 --> 01:01:45,555 And so when we use that template, that's what 1264 01:01:45,555 --> 01:01:47,170 we're going to have to bear in mind. 1265 01:01:47,170 --> 01:01:50,490 So what goes on in the code to allow that to function? 1266 01:01:50,490 --> 01:01:53,410 Well, down here in the body, I have an input field. 1267 01:01:53,410 --> 01:01:54,160 Its id is counter. 1268 01:01:54,160 --> 01:01:56,993 That's just going to be the place where I can type in how many rolls 1269 01:01:56,993 --> 01:01:57,930 I actually care about. 1270 01:01:57,930 --> 01:02:02,350 I have a button just like before and an unordered list just like before. 1271 01:02:02,350 --> 01:02:05,280 So what happens now when I roll? 1272 01:02:05,280 --> 01:02:07,650 Well, rather than just keep track of a single roll, 1273 01:02:07,650 --> 01:02:09,260 I'm going to keep track of an array of rolls. 1274 01:02:09,260 --> 01:02:11,176 So I'm defining a variable called rolls, which 1275 01:02:11,176 --> 01:02:13,170 is just going to start out as this empty array, 1276 01:02:13,170 --> 01:02:16,470 and it'll also keep track of the total as I go. 1277 01:02:16,470 --> 01:02:18,750 So after I've gotten this counter of how many rolls 1278 01:02:18,750 --> 01:02:23,000 I want to run just by getting at the value of whatever that input field is,. 1279 01:02:23,000 --> 01:02:25,650 Here's the for loop that actually lets me repeat 1280 01:02:25,650 --> 01:02:27,720 these random rolls over and over again. 1281 01:02:27,720 --> 01:02:30,630 I get a new value that is the value of that new roll. 1282 01:02:30,630 --> 01:02:33,272 I push it onto the end of this array of rolls, 1283 01:02:33,272 --> 01:02:36,480 and then I update the total to reflect the fact that that's a new roll that I 1284 01:02:36,480 --> 01:02:38,970 want to add to my existing total. 1285 01:02:38,970 --> 01:02:41,520 So at the end of this, I have a variable called total, 1286 01:02:41,520 --> 01:02:44,430 which is the total value of all the rolls that I've done. 1287 01:02:44,430 --> 01:02:50,280 And I have this array of rolls that is going to be each roll in this array. 1288 01:02:50,280 --> 01:02:53,987 Finally, I run this template, passing in all those values. 1289 01:02:53,987 --> 01:02:56,070 This is going to be that array of different rolls, 1290 01:02:56,070 --> 01:02:57,920 passing in that integer total. 1291 01:02:57,920 --> 01:03:05,010 Save the result as this variable content and then add that content to the rolls 1292 01:03:05,010 --> 01:03:08,800 unordered list that I have in the HTML page. 1293 01:03:08,800 --> 01:03:13,770 So if I now open dice.html, that's what allows me to now say, 1294 01:03:13,770 --> 01:03:15,840 here's the number of rolls that I want to roll. 1295 01:03:15,840 --> 01:03:17,410 And I can plug-in any number. 1296 01:03:17,410 --> 01:03:20,850 And that's what allows me to loop over, adding one image for each one. 1297 01:03:20,850 --> 01:03:23,050 And then at the end, displaying a total. 1298 01:03:23,050 --> 01:03:25,860 So you can see how using and taking advantage of these Handlebars 1299 01:03:25,860 --> 01:03:30,240 templates, you can begin to build more complicated, more sophisticated user 1300 01:03:30,240 --> 01:03:33,450 interfaces, all by just defining your templates the right way 1301 01:03:33,450 --> 01:03:37,170 and allowing them to do whatever we want them to do. 1302 01:03:37,170 --> 01:03:39,776 Questions so far? 1303 01:03:39,776 --> 01:03:41,650 One final thing before we take a quick break. 1304 01:03:41,650 --> 01:03:44,040 Let's take the same idea of templating and apply it 1305 01:03:44,040 --> 01:03:46,800 to our infinite list of posts, as we did before. 1306 01:03:46,800 --> 01:03:49,715 Remember that before we had to create a new element for the dev. 1307 01:03:49,715 --> 01:03:51,840 We had to create a new element for the Hide button. 1308 01:03:51,840 --> 01:03:53,839 And that was starting to get a little bit messy. 1309 01:03:53,839 --> 01:03:56,620 How can we begin to simplify that process? 1310 01:03:56,620 --> 01:04:00,720 Let's take a look at post2 index.html. 1311 01:04:00,720 --> 01:04:05,100 Now what I have is rather than having to create those elements using 1312 01:04:05,100 --> 01:04:10,440 document.createElement, I just have a script template and Handlebars template 1313 01:04:10,440 --> 01:04:13,920 that defines a div that is going to be a post, and then the contents, 1314 01:04:13,920 --> 01:04:16,330 using curly brace, curly brace, contents. 1315 01:04:16,330 --> 01:04:19,200 Now one strange thing you'll notice about this particular template 1316 01:04:19,200 --> 01:04:23,040 is that I needed to enclose it inside of this raw block. 1317 01:04:23,040 --> 01:04:28,179 Any ideas why I needed to do that here when I didn't before? 1318 01:04:28,179 --> 01:04:29,220 It's a little bit subtle. 1319 01:04:29,220 --> 01:04:32,380 1320 01:04:32,380 --> 01:04:36,610 So this double curly brace syntax really has two different meanings, 1321 01:04:36,610 --> 01:04:38,352 depending on when we're looking at it. 1322 01:04:38,352 --> 01:04:40,060 When Flask is running our web application 1323 01:04:40,060 --> 01:04:41,890 and tries to render a template, we recall 1324 01:04:41,890 --> 01:04:46,280 that the double curly braces was Jinja's way of saying plug in a value here. 1325 01:04:46,280 --> 01:04:49,300 Likewise, in Handlebars, when we're using Handlebars in JavaScript 1326 01:04:49,300 --> 01:04:51,700 to try and create a template, this double curly braces 1327 01:04:51,700 --> 01:04:53,860 also means plug in a value here. 1328 01:04:53,860 --> 01:04:56,270 And because the Flask stuff happens first-- 1329 01:04:56,270 --> 01:05:00,700 because we render this HTML page using Flask and Jinja before it ever 1330 01:05:00,700 --> 01:05:04,360 reaches the client-- before Handlebars ever starts running. 1331 01:05:04,360 --> 01:05:06,820 If we just had double curly brace contents, 1332 01:05:06,820 --> 01:05:10,870 Jinja is going to try and plug in some value called contents into this page. 1333 01:05:10,870 --> 01:05:14,590 But of course, that's not what we want because contents isn't something 1334 01:05:14,590 --> 01:05:16,330 that should be plugged in by Jinja. 1335 01:05:16,330 --> 01:05:18,670 It's something that should be plugged in by Handlebars 1336 01:05:18,670 --> 01:05:21,080 when we go about in JavaScript creating this template. 1337 01:05:21,080 --> 01:05:25,400 And so this raw block is Jinja's way of saying, ignore the contents of here. 1338 01:05:25,400 --> 01:05:27,460 Don't try and mess with the templating but just 1339 01:05:27,460 --> 01:05:31,100 leave it alone and let it get passed back to the client. 1340 01:05:31,100 --> 01:05:35,720 So that template allows us to create the post and add the Hide button. 1341 01:05:35,720 --> 01:05:40,380 And as a result of that, now rather than need to create new elements, 1342 01:05:40,380 --> 01:05:45,850 all we need to do is create a new post template, 1343 01:05:45,850 --> 01:05:48,310 passing in the contents of it, and then add 1344 01:05:48,310 --> 01:05:52,300 that to my do that contains all of those posts. 1345 01:05:52,300 --> 01:05:55,720 So no need to do all those document.createElement 1346 01:05:55,720 --> 01:05:58,850 and assigning a class name in the innerHTML. 1347 01:05:58,850 --> 01:06:03,160 All of that is taken care of for us just by this HTML email template. 1348 01:06:03,160 --> 01:06:08,070 And so if I now go into post2 and run that, 1349 01:06:08,070 --> 01:06:10,680 the result is very much the same as what we've seen before. 1350 01:06:10,680 --> 01:06:12,352 We have this infinite list of posts. 1351 01:06:12,352 --> 01:06:13,810 We're going to scroll through them. 1352 01:06:13,810 --> 01:06:15,730 It generates new posts as well. 1353 01:06:15,730 --> 01:06:18,021 And so that's taking what we've learned from JavaScript 1354 01:06:18,021 --> 01:06:21,125 and templating with Handlebars and applying it to this situation as well. 1355 01:06:21,125 --> 01:06:24,000 When we come back from the break, we'll take a look at some animation 1356 01:06:24,000 --> 01:06:26,670 and how we can begin to do a little bit more with graphics 1357 01:06:26,670 --> 01:06:29,030 and actually making these websites even more dynamic. 1358 01:06:29,030 --> 01:06:31,430 We'll take a short break first. 1359 01:06:31,430 --> 01:06:32,889 OK welcome back. 1360 01:06:32,889 --> 01:06:35,680 So we've been talking about how we can build web applications using 1361 01:06:35,680 --> 01:06:36,850 Python and JavaScript. 1362 01:06:36,850 --> 01:06:38,830 In particular, lately, using JavaScript to help 1363 01:06:38,830 --> 01:06:40,538 make our web pages a little more dynamic, 1364 01:06:40,538 --> 01:06:43,300 to make them responsive to when a user clicks on something 1365 01:06:43,300 --> 01:06:45,910 or when a user scrolls through something to allow the website 1366 01:06:45,910 --> 01:06:47,509 to update itself in response. 1367 01:06:47,509 --> 01:06:49,300 So we're going to continue along that train 1368 01:06:49,300 --> 01:06:51,430 of trying to make our websites more dynamic, 1369 01:06:51,430 --> 01:06:54,040 allowing for things to change and be manipulated 1370 01:06:54,040 --> 01:06:55,501 as things happen on the page. 1371 01:06:55,501 --> 01:06:58,250 And in particular, we're going to get into the topic of animation. 1372 01:06:58,250 --> 01:07:00,083 And so there are all sorts of different ways 1373 01:07:00,083 --> 01:07:03,192 to animate different elements on the HTML page using graphics 1374 01:07:03,192 --> 01:07:04,150 and so on and so forth. 1375 01:07:04,150 --> 01:07:05,780 We'll look at a couple of them today. 1376 01:07:05,780 --> 01:07:09,700 And what we'll begin with is by taking a look back at CSS, 1377 01:07:09,700 --> 01:07:12,640 which we've used previously in order to style different aspects 1378 01:07:12,640 --> 01:07:15,820 of our website-- to be able to change the color of a particular element, 1379 01:07:15,820 --> 01:07:17,830 or add a background to a particular element, 1380 01:07:17,830 --> 01:07:20,080 or change the size of an element, for instance. 1381 01:07:20,080 --> 01:07:23,790 But what CSS also allows us to do-- in the latest versions of CSS, at least-- 1382 01:07:23,790 --> 01:07:26,500 is have what we call CSS animation or the ability 1383 01:07:26,500 --> 01:07:30,460 to change from one CSS property to another CSS property 1384 01:07:30,460 --> 01:07:33,900 over some duration of time, while the page is running. 1385 01:07:33,900 --> 01:07:35,650 And so what that's going to allow us to do 1386 01:07:35,650 --> 01:07:39,580 is allow us to begin to animate content on our page 1387 01:07:39,580 --> 01:07:42,940 in order to allow it to change its style properties. 1388 01:07:42,940 --> 01:07:47,172 And at first, this might seem like just interesting things that are cool to do, 1389 01:07:47,172 --> 01:07:48,880 but we'll soon see practical implications 1390 01:07:48,880 --> 01:07:52,690 for how being able to manipulate the style using CSS animation 1391 01:07:52,690 --> 01:07:54,940 can actually be very relevant and helpful as we 1392 01:07:54,940 --> 01:07:57,400 go about building our web applications. 1393 01:07:57,400 --> 01:08:02,710 And so the first thing we'll take a look at is animate0.html. 1394 01:08:02,710 --> 01:08:08,140 So animate0.html is a very simple HTML page that inside of the body 1395 01:08:08,140 --> 01:08:10,780 just has an h1 heading that says welcome. 1396 01:08:10,780 --> 01:08:14,290 And what's interesting is what's contained inside 1397 01:08:14,290 --> 01:08:19,060 of the CSS code-- so inside of the style block of this particular page. 1398 01:08:19,060 --> 01:08:22,899 This is where all of the relevant CSS animation is actually happening. 1399 01:08:22,899 --> 01:08:25,420 What we're doing up here with this at keyframes 1400 01:08:25,420 --> 01:08:30,910 grow is defining an animation-- a CSS animation that we're calling grow. 1401 01:08:30,910 --> 01:08:33,649 And what happens inside of the grow animation? 1402 01:08:33,649 --> 01:08:35,920 Well, we're going to go from something to something-- 1403 01:08:35,920 --> 01:08:40,399 from some set of CSS properties to some other set of CSS properties. 1404 01:08:40,399 --> 01:08:44,800 And in this case, we're going to go from font size 20 pixels to font size 1405 01:08:44,800 --> 01:08:46,420 100 pixels. 1406 01:08:46,420 --> 01:08:50,220 So grow is a CSS animation that causes the font size of whatever it 1407 01:08:50,220 --> 01:08:52,300 is applied to to grow. 1408 01:08:52,300 --> 01:08:54,819 An so now we have this h1 styling that is 1409 01:08:54,819 --> 01:08:58,479 going to be applied to that welcome heading that we have down below, 1410 01:08:58,479 --> 01:09:01,020 and we're giving it a couple of its own CSS properties. 1411 01:09:01,020 --> 01:09:03,970 First, giving it an animation name, grow. 1412 01:09:03,970 --> 01:09:06,100 And because this lines up with the grow up here, 1413 01:09:06,100 --> 01:09:08,590 that's saying that we want this h1 to have 1414 01:09:08,590 --> 01:09:11,649 this keyframe animation-- this animation of font size 20 1415 01:09:11,649 --> 01:09:15,189 to font size 100 to be applied to it. 1416 01:09:15,189 --> 01:09:18,576 Animation duration is just how long that animation should last. 1417 01:09:18,576 --> 01:09:21,700 In this case, we're saying 2 seconds seems like a reasonable amount of time 1418 01:09:21,700 --> 01:09:22,930 for an animation. 1419 01:09:22,930 --> 01:09:26,410 And then animation film mode is a special CSS 1420 01:09:26,410 --> 01:09:30,460 property that means in what direction should the animation go? 1421 01:09:30,460 --> 01:09:32,410 And by going forwards, were sort of saying 1422 01:09:32,410 --> 01:09:34,840 once we reach the end of the animation, we should 1423 01:09:34,840 --> 01:09:37,060 keep that state that we end up in. 1424 01:09:37,060 --> 01:09:41,200 In other words, if we move from 20 pixels to 100 pixels in font size, 1425 01:09:41,200 --> 01:09:44,830 then after the animation is done running, we should stay at 100 pixels, 1426 01:09:44,830 --> 01:09:47,490 instead of going back to 20, for instance. 1427 01:09:47,490 --> 01:09:49,689 And so by defining these three properties, 1428 01:09:49,689 --> 01:09:54,850 we're now telling are h1 heading to undergo this grow animation. 1429 01:09:54,850 --> 01:09:58,960 And the result of that is if we open up animate0.html, 1430 01:09:58,960 --> 01:10:00,400 which is just an HTML page. 1431 01:10:00,400 --> 01:10:04,660 We have added no flask backend, no Python here, no JavaScript even. 1432 01:10:04,660 --> 01:10:06,580 Just a CSS animation. 1433 01:10:06,580 --> 01:10:13,620 And now when I open up animate0, we see welcome over the course of two seconds, 1434 01:10:13,620 --> 01:10:14,400 grow in size. 1435 01:10:14,400 --> 01:10:17,250 And it stays in that size as a result. So that 1436 01:10:17,250 --> 01:10:21,127 was just a very basic introduction to what CSS animations can do. 1437 01:10:21,127 --> 01:10:24,210 And while they can't be used for all CSS properties-- for many properties, 1438 01:10:24,210 --> 01:10:28,980 including the size of text, for instance, we can apply CSS animation. 1439 01:10:28,980 --> 01:10:31,400 Questions so far? 1440 01:10:31,400 --> 01:10:33,830 OK, let's take a look at one more example before we start 1441 01:10:33,830 --> 01:10:38,240 to look at some practical uses of this. 1442 01:10:38,240 --> 01:10:44,450 Here's animate1.html, which likewise defines just this h1, welcome. 1443 01:10:44,450 --> 01:10:47,930 And here's the interesting style code that's happening. 1444 01:10:47,930 --> 01:10:51,397 We've defined this keyframe animation called move. 1445 01:10:51,397 --> 01:10:53,480 And what's going to happen in the movie animation? 1446 01:10:53,480 --> 01:10:58,490 We're going to move from left 0% to left 50%. 1447 01:10:58,490 --> 01:11:01,220 And what this means is that left is a way 1448 01:11:01,220 --> 01:11:05,570 of indicating the relative position of an HTML element. 1449 01:11:05,570 --> 01:11:09,020 And this h1, you've noticed we've given a position of relative, 1450 01:11:09,020 --> 01:11:12,380 meaning we're going to define the position of this heading relative 1451 01:11:12,380 --> 01:11:13,970 to other parts of the window. 1452 01:11:13,970 --> 01:11:17,660 In particular, at the beginning, when we start to move animation, 1453 01:11:17,660 --> 01:11:21,690 it's going to be 0% of the window away from the left edge of the screen. 1454 01:11:21,690 --> 01:11:24,470 In other words, it's going to be at the left edge of the screen. 1455 01:11:24,470 --> 01:11:29,730 And then it's going to move to being 50% away from the left edge of the screen. 1456 01:11:29,730 --> 01:11:31,970 In other words, the left side of the HTML element 1457 01:11:31,970 --> 01:11:34,730 will be aligned with the middle of the window. 1458 01:11:34,730 --> 01:11:38,600 And so this is not a change in size but a change in position. 1459 01:11:38,600 --> 01:11:41,600 We are allowing ourselves to change the position of the HTML element, 1460 01:11:41,600 --> 01:11:44,840 moving it from the left side of the screen to the middle of the screen 1461 01:11:44,840 --> 01:11:47,510 just by applying this move animation to it. 1462 01:11:47,510 --> 01:11:51,620 And so very similar to what animate0 was doing, except instead of changing size, 1463 01:11:51,620 --> 01:11:55,320 we're not changing the position of this relatively positioned element. 1464 01:11:55,320 --> 01:11:58,760 And so if we open animate1, the result is 1465 01:11:58,760 --> 01:12:01,444 that over the course of a couple of seconds, that welcome moves 1466 01:12:01,444 --> 01:12:02,610 from the left to the center. 1467 01:12:02,610 --> 01:12:03,943 We're going to watch that again. 1468 01:12:03,943 --> 01:12:09,020 It goes from the left up until 50% away from the left edge of the screen. 1469 01:12:09,020 --> 01:12:13,040 And so that's what allows us to begin to build up this vocabulary of ways 1470 01:12:13,040 --> 01:12:17,700 to animate HTML elements and move them from one place to another. 1471 01:12:17,700 --> 01:12:20,300 But what might be helpful here is not just 1472 01:12:20,300 --> 01:12:24,440 defining a starting and an endpoint but also some intermediary points 1473 01:12:24,440 --> 01:12:25,190 in that animation. 1474 01:12:25,190 --> 01:12:28,100 Now say we want to start it in some place, move it somewhere else, 1475 01:12:28,100 --> 01:12:30,120 and then move somewhere else at the end of it. 1476 01:12:30,120 --> 01:12:33,600 And so in addition to just saying move from something to something else, 1477 01:12:33,600 --> 01:12:36,950 we also have the ability to define at what percentage 1478 01:12:36,950 --> 01:12:39,080 of the way through an animation should we 1479 01:12:39,080 --> 01:12:41,850 be applying particular CSS properties? 1480 01:12:41,850 --> 01:12:43,590 So what does that look like? 1481 01:12:43,590 --> 01:12:45,830 Let's look at animate2.html. 1482 01:12:45,830 --> 01:12:48,830 And in this move keyframe, we're doing something 1483 01:12:48,830 --> 01:12:51,770 slightly different rather than from something to something else, 1484 01:12:51,770 --> 01:12:56,360 we're saying at 0% of the way through the animation, 1485 01:12:56,360 --> 01:12:59,180 we should be 0% of the way from the left edge. 1486 01:12:59,180 --> 01:13:01,520 At 50% of the way through the animation, we 1487 01:13:01,520 --> 01:13:03,444 should be 50% away from the left edge. 1488 01:13:03,444 --> 01:13:06,360 And at 100% of the way through the animation, when we're done with it, 1489 01:13:06,360 --> 01:13:08,820 we should be 0% away from the left edge. 1490 01:13:08,820 --> 01:13:12,800 What is this going to look like if I try and apply this same move animation 1491 01:13:12,800 --> 01:13:15,920 to the heading that we had before? 1492 01:13:15,920 --> 01:13:21,068 Based on these three keyframes as part of this animation. 1493 01:13:21,068 --> 01:13:22,735 AUDIENCE: [INAUDIBLE] middle [INAUDIBLE] 1494 01:13:22,735 --> 01:13:24,442 BRIAN YU: Go to the middle and come back. 1495 01:13:24,442 --> 01:13:26,300 At 50% of the way, it will be at the middle. 1496 01:13:26,300 --> 01:13:28,216 When it's all the way done, it will come back. 1497 01:13:28,216 --> 01:13:32,330 And so if I open up animate2.html, it goes to the middle halfway through 1498 01:13:32,330 --> 01:13:33,750 and then it comes back. 1499 01:13:33,750 --> 01:13:34,520 Excellent. 1500 01:13:34,520 --> 01:13:37,757 So that was all well and good, but what we noticed so far 1501 01:13:37,757 --> 01:13:39,590 is that we don't have a whole lot of control 1502 01:13:39,590 --> 01:13:42,110 over when this animation takes place. 1503 01:13:42,110 --> 01:13:43,850 We open up the page. 1504 01:13:43,850 --> 01:13:46,160 And because the CSS properties are already 1505 01:13:46,160 --> 01:13:48,500 assigned at the beginning of the web page being run, 1506 01:13:48,500 --> 01:13:52,310 it's just automatically going to start performing the animation, 1507 01:13:52,310 --> 01:13:54,560 moving welcome to the middle, and then moving it back. 1508 01:13:54,560 --> 01:13:58,070 But maybe we only want animations to happen at a certain point in time. 1509 01:13:58,070 --> 01:14:00,239 When we decide that we won't be animation to run, 1510 01:14:00,239 --> 01:14:01,280 the animation should run. 1511 01:14:01,280 --> 01:14:03,470 And when we don't want it to run, it shouldn't run. 1512 01:14:03,470 --> 01:14:06,380 And to do that, we'll need a little more than just CSS. 1513 01:14:06,380 --> 01:14:08,870 We could using CSS delay the animation. 1514 01:14:08,870 --> 01:14:12,614 Say don't have the animation start until 3 seconds after the page loads, 1515 01:14:12,614 --> 01:14:14,030 but that's not quite what we want. 1516 01:14:14,030 --> 01:14:17,150 What we want is the ability to programmatically control 1517 01:14:17,150 --> 01:14:18,960 when the animation starts and stops. 1518 01:14:18,960 --> 01:14:21,920 And to do that, we'll need a programming language like JavaScript. 1519 01:14:21,920 --> 01:14:28,760 And so one additional CSS property that these animations have is they 1520 01:14:28,760 --> 01:14:31,640 have a property called animation play state 1521 01:14:31,640 --> 01:14:34,790 that that property can be either paused or running. 1522 01:14:34,790 --> 01:14:37,970 And so if the play state of a CSS animation is paused, 1523 01:14:37,970 --> 01:14:39,290 nothing is going to happen. 1524 01:14:39,290 --> 01:14:42,920 But if we use JavaScript to change it to running instead of paused, 1525 01:14:42,920 --> 01:14:44,930 now the animation will be running. 1526 01:14:44,930 --> 01:14:49,850 So let's take a look at animate3.html. 1527 01:14:49,850 --> 01:14:52,080 The CSS is still the same. 1528 01:14:52,080 --> 01:14:56,180 We have this move animation that's going to go from the left to the middle back 1529 01:14:56,180 --> 01:14:58,400 to the left again. 1530 01:14:58,400 --> 01:15:01,460 And then in each one, we have animation name 1531 01:15:01,460 --> 01:15:03,920 is move, all this additional information. 1532 01:15:03,920 --> 01:15:07,010 We have also animation-iteration-count infinite. 1533 01:15:07,010 --> 01:15:10,790 So animation-iteration-count is a CSS property 1534 01:15:10,790 --> 01:15:14,040 that allows us to specify how many times an animation should run. 1535 01:15:14,040 --> 01:15:16,030 Should it run 2 times, 3 times, 4 times. 1536 01:15:16,030 --> 01:15:17,409 Infinite just means keep running. 1537 01:15:17,409 --> 01:15:19,950 So it'll go to the center and to the left again to the center 1538 01:15:19,950 --> 01:15:23,510 and to the left again, over and over and over again infinitely. 1539 01:15:23,510 --> 01:15:27,130 And here is the JavaScript that we want. 1540 01:15:27,130 --> 01:15:31,210 So we're going to first select this h1 element 1541 01:15:31,210 --> 01:15:35,580 and set its animationPlayState to paused. 1542 01:15:35,580 --> 01:15:38,080 So right off the bat, when we first load the page, 1543 01:15:38,080 --> 01:15:40,270 we're going to pause the animation because we don't 1544 01:15:40,270 --> 01:15:42,130 want it to run when we first load it. 1545 01:15:42,130 --> 01:15:46,222 What we do want to happen though is we want to attach a button 1546 01:15:46,222 --> 01:15:47,180 to do something useful. 1547 01:15:47,180 --> 01:15:48,220 So we have this button. 1548 01:15:48,220 --> 01:15:51,690 We're going to say when the button is clicked If the current PlayState 1549 01:15:51,690 --> 01:15:55,000 state of this heading is paused, then go ahead and change 1550 01:15:55,000 --> 01:15:57,420 the PlayState to run it. 1551 01:15:57,420 --> 01:16:00,537 Otherwise, change the PlayState back to paused. 1552 01:16:00,537 --> 01:16:03,120 And so what that's going to mean is if the animation is paused 1553 01:16:03,120 --> 01:16:04,110 like it is to start out with. 1554 01:16:04,110 --> 01:16:06,990 And we click the button, then it's going to change from pause to running. 1555 01:16:06,990 --> 01:16:07,650 If it's running. 1556 01:16:07,650 --> 01:16:10,733 And we click the button, then it's going to change from running to paused. 1557 01:16:10,733 --> 01:16:13,560 And in the body here, all we have is a button that says click here 1558 01:16:13,560 --> 01:16:16,170 and a heading that says welcome. 1559 01:16:16,170 --> 01:16:18,960 So if we open ue3.html. 1560 01:16:18,960 --> 01:16:20,910 Now we have the ability to just see welcome, 1561 01:16:20,910 --> 01:16:22,493 which right now is not doing anything. 1562 01:16:22,493 --> 01:16:23,790 Its playState is paused. 1563 01:16:23,790 --> 01:16:29,124 But clicking on the button causes the playState to change to running 1564 01:16:29,124 --> 01:16:31,790 and now welcome is going to bounce back and forth between middle 1565 01:16:31,790 --> 01:16:33,490 of the page and left side of the page. 1566 01:16:33,490 --> 01:16:36,530 And for it to click here, now I've paused the animation again. 1567 01:16:36,530 --> 01:16:37,341 Now it's paused. 1568 01:16:37,341 --> 01:16:38,840 But I can start and stop it at will. 1569 01:16:38,840 --> 01:16:42,730 Whenever I decide to click on it, I can start and stop that animation. 1570 01:16:42,730 --> 01:16:45,110 So now I have programmatic control using JavaScript 1571 01:16:45,110 --> 01:16:47,090 over when that animation happens. 1572 01:16:47,090 --> 01:16:48,710 And so this is fun. 1573 01:16:48,710 --> 01:16:52,490 But now let's actually I a case where it might be nice for a user interface 1574 01:16:52,490 --> 01:16:54,410 to build in some of this animation. 1575 01:16:54,410 --> 01:16:57,890 And so one thing you might have noticed is we 1576 01:16:57,890 --> 01:17:01,160 looked at that infinite scroll list of posts earlier before the break 1577 01:17:01,160 --> 01:17:04,670 where when I ran this application 1578 01:17:04,670 --> 01:17:06,500 We saw this infinite list of posts. 1579 01:17:06,500 --> 01:17:08,250 And right now, there are only 20, here. 1580 01:17:08,250 --> 01:17:11,240 But if I ever were to hide a post-- if I hide post number two. 1581 01:17:11,240 --> 01:17:12,600 Post 2 goes away. 1582 01:17:12,600 --> 01:17:13,850 And now I have post1 one. 1583 01:17:13,850 --> 01:17:15,500 Jumping straight to plus 3? 1584 01:17:15,500 --> 01:17:20,870 What was less than ideal about that usee Interface experience just then? 1585 01:17:20,870 --> 01:17:21,440 Any thoughts? 1586 01:17:21,440 --> 01:17:23,120 AUDIENCE: You didn't really see the posts going away. 1587 01:17:23,120 --> 01:17:25,250 BRIAN YU: Yeah, you didn't really see the post going away, 1588 01:17:25,250 --> 01:17:27,090 especially because all these posts are the same length, 1589 01:17:27,090 --> 01:17:29,173 and they're all the same size, like if I hide post 1590 01:17:29,173 --> 01:17:31,400 for you really need to be paying attention to notice 1591 01:17:31,400 --> 01:17:33,425 that a jump from plus 3 to post 5. 1592 01:17:33,425 --> 01:17:36,050 So this is a case where animation might actually come into play 1593 01:17:36,050 --> 01:17:38,810 and help the user interface if we can actually animate something 1594 01:17:38,810 --> 01:17:40,190 to mean the post is going 1595 01:17:40,190 --> 01:17:43,730 Away, that might make it a more enjoyable user experience 1596 01:17:43,730 --> 01:17:45,360 for whoever is looking at the page. 1597 01:17:45,360 --> 01:17:53,381 So let's take a look now at post3 and look at index.html there. 1598 01:17:53,381 --> 01:17:55,130 And what you've noticed here is that we're 1599 01:17:55,130 --> 01:18:00,450 going to add an animation here called hide it inside of the CSS. 1600 01:18:00,450 --> 01:18:04,474 And it's going to go from opacity one to opacity zero. 1601 01:18:04,474 --> 01:18:06,890 Opacity is just a measure of how transparent something is. 1602 01:18:06,890 --> 01:18:08,970 Opacity 1 means you can see it entirely. 1603 01:18:08,970 --> 01:18:10,910 Opacity 0 means it's completely transparent. 1604 01:18:10,910 --> 01:18:12,870 You can't see it at all. 1605 01:18:12,870 --> 01:18:18,740 So if we apply this hide animation to our posts, To all of our posts 1606 01:18:18,740 --> 01:18:20,002 are going to have class post. 1607 01:18:20,002 --> 01:18:21,710 And I say this is going to have animation 1608 01:18:21,710 --> 01:18:24,320 named hide the animation duration of two seconds 1609 01:18:24,320 --> 01:18:25,920 will take two seconds to hide it. 1610 01:18:25,920 --> 01:18:27,045 It's going to move forward. 1611 01:18:27,045 --> 01:18:29,780 So it goes transparent, it will stay transparent. 1612 01:18:29,780 --> 01:18:32,780 And a place state is going to start out is paused because at first, we 1613 01:18:32,780 --> 01:18:33,946 don't want it to be running. 1614 01:18:33,946 --> 01:18:37,650 Otherwise, all the posts are going to disappear right away. 1615 01:18:37,650 --> 01:18:39,570 So when does this actually happen? 1616 01:18:39,570 --> 01:18:46,700 Well, when the Hide button is clicked, and this 1617 01:18:46,700 --> 01:18:50,360 is a slightly different way of applying the logic of when the Hide button is 1618 01:18:50,360 --> 01:18:53,660 click but basically I'm saying when anything is clicked 1619 01:18:53,660 --> 01:18:56,150 figure out what with click the element that was clicked. 1620 01:18:56,150 --> 01:18:59,810 And if that element has class name hide in other words, if we are clicking. 1621 01:18:59,810 --> 01:19:01,130 on a Hide button. 1622 01:19:01,130 --> 01:19:03,990 Then we should take the Hide buttons parent element. 1623 01:19:03,990 --> 01:19:08,510 In other words, the post itself change its animationPlayState to be running. 1624 01:19:08,510 --> 01:19:11,285 Now we want the animation to run-- this hide animation. 1625 01:19:11,285 --> 01:19:13,160 And now we can also add these eventListeners. 1626 01:19:13,160 --> 01:19:16,040 So we can say, all right, for this entire post, 1627 01:19:16,040 --> 01:19:19,140 at an eventListener that says animationEnd-- in other words, 1628 01:19:19,140 --> 01:19:23,030 when the animation is done running run this function, which 1629 01:19:23,030 --> 01:19:25,380 just removes the parent element. 1630 01:19:25,380 --> 01:19:28,610 So in other words, what all of this is doing is that when a Hide button is 1631 01:19:28,610 --> 01:19:32,570 clicked we get the parentElement of the Hide button-- this entire post-- 1632 01:19:32,570 --> 01:19:34,940 we start running this hiding animation. 1633 01:19:34,940 --> 01:19:38,360 When the animation is done running, when the thing is totally transparent, 1634 01:19:38,360 --> 01:19:41,220 now we remove the element altogether. 1635 01:19:41,220 --> 01:19:45,950 And so the result of this is that if I go into plus 3 and run that. 1636 01:19:45,950 --> 01:19:48,740 1637 01:19:48,740 --> 01:19:50,150 Now I see all the posts. 1638 01:19:50,150 --> 01:19:52,700 If I try and hide posts number 2, for instance, 1639 01:19:52,700 --> 01:19:56,950 over the course of two seconds, it goes transparent, and now the post is gone. 1640 01:19:56,950 --> 01:19:59,860 So you have this animation that changes the transparency of the post. 1641 01:19:59,860 --> 01:20:03,790 That makes it very clear that that post is disappearing. 1642 01:20:03,790 --> 01:20:07,007 I had one additional thought for how to make this user experience any better. 1643 01:20:07,007 --> 01:20:09,340 Do you guys have any thoughts on how we can improve this 1644 01:20:09,340 --> 01:20:10,840 even more make it a little smoother? 1645 01:20:10,840 --> 01:20:14,090 1646 01:20:14,090 --> 01:20:16,820 Yeah, it'd be nice if we're sort of used to the idea 1647 01:20:16,820 --> 01:20:18,740 that things will sort of slide into place. 1648 01:20:18,740 --> 01:20:21,990 Right now, when I click the Hide button on posts6, it disappears. 1649 01:20:21,990 --> 01:20:24,737 And now as soon as the element's removed, everything pops up. 1650 01:20:24,737 --> 01:20:26,570 And the reason why that happens is that when 1651 01:20:26,570 --> 01:20:29,470 we change the opacity of the element, the element is still there. 1652 01:20:29,470 --> 01:20:31,380 It just now has become transparent. 1653 01:20:31,380 --> 01:20:34,130 And as soon as we remove the element, now everything sort of bumps 1654 01:20:34,130 --> 01:20:35,005 up to fill its place. 1655 01:20:35,005 --> 01:20:38,164 So we never got the idea that things were sort of sliding into place. 1656 01:20:38,164 --> 01:20:40,580 And so let's try and build that out now with a little more 1657 01:20:40,580 --> 01:20:47,600 sophisticated animation by taking a look at post 4, index.html. 1658 01:20:47,600 --> 01:20:49,530 And so this one's a little more complicated, 1659 01:20:49,530 --> 01:20:51,530 but we'll walk through it slowly. 1660 01:20:51,530 --> 01:20:55,610 The way that we're going to simulate the idea of hiding the post 1661 01:20:55,610 --> 01:20:57,830 is by shrinking the height of the post. 1662 01:20:57,830 --> 01:21:00,530 So if we can get the post to be of height 0-- to have no height, 1663 01:21:00,530 --> 01:21:03,650 to have the text not have any height, to have no padding 1664 01:21:03,650 --> 01:21:05,870 or spacing around the post, that's effectively 1665 01:21:05,870 --> 01:21:07,940 meaning that this post no longer has a height. 1666 01:21:07,940 --> 01:21:10,520 And that will simulate the idea of sliding into place. 1667 01:21:10,520 --> 01:21:14,150 And so at 0%, when this animation begins, 1668 01:21:14,150 --> 01:21:17,390 we're going to start at full opacity, and all of this height information 1669 01:21:17,390 --> 01:21:20,180 is going to be its maximum height is going to be 100%. 1670 01:21:20,180 --> 01:21:21,767 The line height to 100%. 1671 01:21:21,767 --> 01:21:23,600 If you looked at the CSS later, you'd notice 1672 01:21:23,600 --> 01:21:26,150 we have 20 pixels of padding and a 10-pixel margin. 1673 01:21:26,150 --> 01:21:29,270 So all of that padding and margin is still there. 1674 01:21:29,270 --> 01:21:33,042 75% of the way through the animation-- for the first 75% of the animation, 1675 01:21:33,042 --> 01:21:35,000 we're just going to do the transparency effect. 1676 01:21:35,000 --> 01:21:37,550 We're going to cause the post to fade out. 1677 01:21:37,550 --> 01:21:40,250 And so the result is that everything is the same as before, 1678 01:21:40,250 --> 01:21:41,750 but now the opacity is zero. 1679 01:21:41,750 --> 01:21:44,780 Now the post is totally transparent. 1680 01:21:44,780 --> 01:21:48,710 And now at 100% of the way through, the opacity is still zero. 1681 01:21:48,710 --> 01:21:50,210 It's still totally transparent. 1682 01:21:50,210 --> 01:21:52,220 But now the height of this element is zero. 1683 01:21:52,220 --> 01:21:53,630 Its line height is zero. 1684 01:21:53,630 --> 01:21:55,500 It's got no padding and no margin. 1685 01:21:55,500 --> 01:21:58,670 And so over the course of the last 25% of this animation, 1686 01:21:58,670 --> 01:22:01,160 we're just going to have this transparent post take up 1687 01:22:01,160 --> 01:22:02,282 less and less space. 1688 01:22:02,282 --> 01:22:03,740 So the height is going to decrease. 1689 01:22:03,740 --> 01:22:05,602 Any spacing around it is going to decrease. 1690 01:22:05,602 --> 01:22:08,060 And that's going to ultimately give us the effect of things 1691 01:22:08,060 --> 01:22:09,740 sliding into place. 1692 01:22:09,740 --> 01:22:17,030 And so now if we go ahead and go into posts4 and sorry, run that. 1693 01:22:17,030 --> 01:22:18,110 Open the page. 1694 01:22:18,110 --> 01:22:19,550 We get all the posts to load. 1695 01:22:19,550 --> 01:22:22,310 And now when I click hide, it first fades out, 1696 01:22:22,310 --> 01:22:25,970 then the height shrinks and the posts slide up into place. 1697 01:22:25,970 --> 01:22:26,720 Again, click Hide. 1698 01:22:26,720 --> 01:22:29,332 The first 75% shrinks, and then they slide up into place. 1699 01:22:29,332 --> 01:22:31,790 And the sliding happens because that height gets decreased. 1700 01:22:31,790 --> 01:22:34,470 And at the end, that post just goes away entirely. 1701 01:22:34,470 --> 01:22:38,067 And so using CSS animation, we've been able to create a more enjoyable user 1702 01:22:38,067 --> 01:22:41,150 experience that makes it clear what's happening-- by showing the fade out, 1703 01:22:41,150 --> 01:22:42,880 by showing the sliding up into place. 1704 01:22:42,880 --> 01:22:46,160 And so these are just some of the possible practical applications 1705 01:22:46,160 --> 01:22:49,760 of using CSS animation in order to make our websites more dynamic, more 1706 01:22:49,760 --> 01:22:53,510 interesting, more engaging, and appealing to whoever is using it. 1707 01:22:53,510 --> 01:22:56,861 Questions on anything so far about how any of that worked? 1708 01:22:56,861 --> 01:22:57,360 Yeah? 1709 01:22:57,360 --> 01:23:01,590 AUDIENCE: So is that built into CSS [INAUDIBLE]?? 1710 01:23:01,590 --> 01:23:03,690 BRIAN YU: Yep, it's in the latest version of CSS, 1711 01:23:03,690 --> 01:23:06,900 and all modern browsers nowadays can understand these keyframe animations 1712 01:23:06,900 --> 01:23:07,810 and make them work. 1713 01:23:07,810 --> 01:23:09,090 Great question. 1714 01:23:09,090 --> 01:23:10,817 OK, so that was CSS animation. 1715 01:23:10,817 --> 01:23:12,900 There are all sorts of other ways to do animation. 1716 01:23:12,900 --> 01:23:15,360 We'll take a look at one such example right now, 1717 01:23:15,360 --> 01:23:19,380 and that's the idea of svgs or Scalable Vector Graphics 1718 01:23:19,380 --> 01:23:21,600 that are going to allow us to really draw whatever 1719 01:23:21,600 --> 01:23:23,987 we want onto the canvas of the page. 1720 01:23:23,987 --> 01:23:26,070 So far, when we want to put something on the page, 1721 01:23:26,070 --> 01:23:28,740 we've only really been able to create HTML elements 1722 01:23:28,740 --> 01:23:32,070 like divs, which are just rectangular segments, or buttons or text, 1723 01:23:32,070 --> 01:23:32,910 for instance. 1724 01:23:32,910 --> 01:23:35,760 But maybe we'd like to be able to get whatever arbitrary shapes 1725 01:23:35,760 --> 01:23:38,230 that we want onto the page as well. 1726 01:23:38,230 --> 01:23:42,900 So in order to do that, let's take a look at circle0.html, 1727 01:23:42,900 --> 01:23:47,670 which is a very simple HTML page that is going to define this svg element-- 1728 01:23:47,670 --> 01:23:49,470 this vector graphic element-- 1729 01:23:49,470 --> 01:23:51,690 where a vector graphic is just going to be a graphic 1730 01:23:51,690 --> 01:23:56,040 that's defined in terms of lines and angles 1731 01:23:56,040 --> 01:23:59,110 and shapes that we can programmatically define. 1732 01:23:59,110 --> 01:24:02,610 And so inside of this svg, and I'm saying this vector 1733 01:24:02,610 --> 01:24:04,950 graphic's going to have a height of 800 pixels, what 1734 01:24:04,950 --> 01:24:06,420 I have is a circle element. 1735 01:24:06,420 --> 01:24:10,680 And so this just happens to be one of the vector graphic elements 1736 01:24:10,680 --> 01:24:13,200 that each HTML understands and supports. 1737 01:24:13,200 --> 01:24:17,910 And we're saying this circle will have a center x-coordinate of 200, 1738 01:24:17,910 --> 01:24:21,720 a center y-coordinate of 200, a radius of 50, 1739 01:24:21,720 --> 01:24:23,650 and we can apply CSS styling to it as well. 1740 01:24:23,650 --> 01:24:26,940 We can say fill it with blue that's just CSS there. 1741 01:24:26,940 --> 01:24:31,579 And so we're using this svg element to be able to create a graphic, 1742 01:24:31,579 --> 01:24:33,120 in this case, a very simple graphic-- 1743 01:24:33,120 --> 01:24:34,870 just a circle. 1744 01:24:34,870 --> 01:24:41,860 So if I now open circle0.html, what I get on the page 1745 01:24:41,860 --> 01:24:47,380 is just this blue circle that's located 200 pixels away, 200 pixels away. 1746 01:24:47,380 --> 01:24:48,940 And it's located there. 1747 01:24:48,940 --> 01:24:52,770 It's got a certain radius of 50, I believe, and it's colored in blue. 1748 01:24:52,770 --> 01:24:57,435 And so that was using just this code that web browsers nowadays 1749 01:24:57,435 --> 01:24:58,060 can understand. 1750 01:24:58,060 --> 01:25:01,750 They know how to look at svg, look at the shapes and lines that are defined 1751 01:25:01,750 --> 01:25:05,257 by the svg element, and fill it in. 1752 01:25:05,257 --> 01:25:07,840 But what we might like to do is have a little bit more control 1753 01:25:07,840 --> 01:25:11,110 over this, as usual, where we can define the HTML element here. 1754 01:25:11,110 --> 01:25:14,380 But it would be nice if we could programmatically create a circle, 1755 01:25:14,380 --> 01:25:18,006 such that if we wanted it in a for loop that created 28 different circles, 1756 01:25:18,006 --> 01:25:19,630 for instance, we could do that as well. 1757 01:25:19,630 --> 01:25:22,870 Or if we wanted to apply animations or transitions to it, 1758 01:25:22,870 --> 01:25:24,730 we could control that using JavaScript. 1759 01:25:24,730 --> 01:25:26,560 And so we'll see examples of that as well. 1760 01:25:26,560 --> 01:25:30,370 So what circle1.index.html is-- either it's 1761 01:25:30,370 --> 01:25:34,000 going to be using JavaScript to be able to create programmatically 1762 01:25:34,000 --> 01:25:35,620 that same circle we saw before. 1763 01:25:35,620 --> 01:25:38,175 And to do that, we're going to use a library called D3. 1764 01:25:38,175 --> 01:25:40,300 D3 is a very popular JavaScript library that that's 1765 01:25:40,300 --> 01:25:42,370 especially useful for visualizing data. 1766 01:25:42,370 --> 01:25:45,640 It's good at creating graphs and charts and different types 1767 01:25:45,640 --> 01:25:49,117 of interactive graphics that are interesting and cool to look at. 1768 01:25:49,117 --> 01:25:50,200 It's got tons of features. 1769 01:25:50,200 --> 01:25:52,574 We're not really going to look at most of those features. 1770 01:25:52,574 --> 01:25:54,430 But we're going to use D3 just for the sake 1771 01:25:54,430 --> 01:25:56,730 of being able to create svg elements. 1772 01:25:56,730 --> 01:25:59,290 So being able to create graphics and animate graphics, 1773 01:25:59,290 --> 01:26:01,540 which is one thing that D3 is commonly used for. 1774 01:26:01,540 --> 01:26:06,100 And so in the body right now, I've just defined the svg element-- nothing 1775 01:26:06,100 --> 01:26:07,370 inside of it. 1776 01:26:07,370 --> 01:26:11,160 And what we have here inside of the JavaScript is 1777 01:26:11,160 --> 01:26:13,630 I am creating this variable svg. 1778 01:26:13,630 --> 01:26:18,779 D3.select is just D3's way of getting access to an HTML element to work with. 1779 01:26:18,779 --> 01:26:21,820 And you only would know about this by reading the D3 documentation, which 1780 01:26:21,820 --> 01:26:23,110 is available online. 1781 01:26:23,110 --> 01:26:26,800 And I'm selecting the thing that has is svg, which is the thing up here. 1782 01:26:26,800 --> 01:26:30,040 And so that's my svg element-- this HTML element here. 1783 01:26:30,040 --> 01:26:34,540 And now I can use these special D3 functions 1784 01:26:34,540 --> 01:26:40,210 and say, svg.append, add something new to my vector graphic 800-pixel canvas 1785 01:26:40,210 --> 01:26:42,220 here and go ahead and add a circle. 1786 01:26:42,220 --> 01:26:44,760 I can specify specific attributes just like before-- 1787 01:26:44,760 --> 01:26:48,730 set its x-coordinate to 200, y-coordinate to 200, radius to 90, 1788 01:26:48,730 --> 01:26:51,180 and then fill it in green this time. 1789 01:26:51,180 --> 01:26:53,590 And so this allows me to do all of the same things 1790 01:26:53,590 --> 01:26:56,340 that I was doing before but now programmatically using JavaScript. 1791 01:26:56,340 --> 01:26:59,131 And this gives me a little more flexibility, a little more control, 1792 01:26:59,131 --> 01:27:01,406 where if I wanted the radius to be some random number, 1793 01:27:01,406 --> 01:27:03,280 I could use that math.random function that we 1794 01:27:03,280 --> 01:27:05,316 used before to just generate a random number 1795 01:27:05,316 --> 01:27:06,940 and give it a random radius every time. 1796 01:27:06,940 --> 01:27:10,360 So I get a little more precision over what I want this to look like. 1797 01:27:10,360 --> 01:27:17,064 And so if I open up circle1.html, now I've got a big green circle here. 1798 01:27:17,064 --> 01:27:19,480 And there are all sorts of other things that I can append. 1799 01:27:19,480 --> 01:27:22,860 In addition to circles, I can also have rectangles, 1800 01:27:22,860 --> 01:27:25,500 so I can append a rectangle, for instance, 1801 01:27:25,500 --> 01:27:28,570 give it an x and y-coordinate, give it a width and height. 1802 01:27:28,570 --> 01:27:32,530 And as a result of, that when I open up a rectangle.html, 1803 01:27:32,530 --> 01:27:33,670 you get a big rectangle. 1804 01:27:33,670 --> 01:27:36,295 No need to worry about all the different things you can create. 1805 01:27:36,295 --> 01:27:38,079 You can create an oval. 1806 01:27:38,079 --> 01:27:40,120 You can create arbitrary shapes, where you define 1807 01:27:40,120 --> 01:27:41,744 where the different various points are. 1808 01:27:41,744 --> 01:27:43,990 But the idea here is that programmatically, you 1809 01:27:43,990 --> 01:27:48,070 can begin to create some of these graphical elements that can do things. 1810 01:27:48,070 --> 01:27:51,290 And we'll see examples of how those work soon too. 1811 01:27:51,290 --> 01:27:56,490 So we've been able to create images that appear-- circles, 1812 01:27:56,490 --> 01:27:58,870 or rectangles, or other shapes as well. 1813 01:27:58,870 --> 01:28:01,330 What we might want to do using JavaScript and using D3, 1814 01:28:01,330 --> 01:28:04,450 in particular, is to animate those things-- cause them to move around, 1815 01:28:04,450 --> 01:28:06,020 cause them to do things. 1816 01:28:06,020 --> 01:28:09,340 And so let's take a look at circle2.html. 1817 01:28:09,340 --> 01:28:12,200 It's going to be very similar to what we had before. 1818 01:28:12,200 --> 01:28:15,910 So we define our svg =. 1819 01:28:15,910 --> 01:28:19,090 Then we're going to append to this svg element a circle. 1820 01:28:19,090 --> 01:28:22,690 Give it an x and y-coordinate of 200 and 200, a radius of 50, 1821 01:28:22,690 --> 01:28:27,370 fill it in as blue, and save that circle inside of a variable called c. 1822 01:28:27,370 --> 01:28:31,060 Now what D3 allows us to do is apply transitions 1823 01:28:31,060 --> 01:28:35,020 to these svg elements, which allow us to animate those elements, 1824 01:28:35,020 --> 01:28:38,860 allow us to cause them to change their properties in some way. 1825 01:28:38,860 --> 01:28:43,210 So c.transition-- so as I want to apply some transition to the circle, 1826 01:28:43,210 --> 01:28:45,610 duration says how long should this transition last? 1827 01:28:45,610 --> 01:28:47,380 This should be one second. 1828 01:28:47,380 --> 01:28:50,110 And all of these repeated lines, each of which starts with a dot, 1829 01:28:50,110 --> 01:28:51,550 they could all be one line. 1830 01:28:51,550 --> 01:28:55,194 But oftentimes in D3, you'll see a common paradigm 1831 01:28:55,194 --> 01:28:57,610 to separate these repeated calls onto different lines just 1832 01:28:57,610 --> 01:29:01,670 to make it clear one line at a time-- what's happening at each step. 1833 01:29:01,670 --> 01:29:04,960 So this transition, or this animation, is going to last one second-- 1834 01:29:04,960 --> 01:29:06,600 1,000 milliseconds. 1835 01:29:06,600 --> 01:29:08,470 And what should change about it? 1836 01:29:08,470 --> 01:29:12,250 Well, let's go ahead and change the x-coordinate to be 500, instead of 200. 1837 01:29:12,250 --> 01:29:14,980 Change the y-coordinate to be 500, instead of a few hundred. 1838 01:29:14,980 --> 01:29:17,930 And change the fill color to be red, instead of blue. 1839 01:29:17,930 --> 01:29:22,056 So we're going to move the circle and also change of style-- change 1840 01:29:22,056 --> 01:29:22,680 its fill color. 1841 01:29:22,680 --> 01:29:25,300 1842 01:29:25,300 --> 01:29:30,360 So when I open circle2 now, we saw the blue circle. 1843 01:29:30,360 --> 01:29:32,130 It moved to the other side of the screen. 1844 01:29:32,130 --> 01:29:34,440 It changed its color from blue to red. 1845 01:29:34,440 --> 01:29:36,532 And so that was an animation that I could create. 1846 01:29:36,532 --> 01:29:37,740 And that happened right away. 1847 01:29:37,740 --> 01:29:40,240 It happened as soon as I opened up the page. 1848 01:29:40,240 --> 01:29:42,616 But there are different ways to delay animations as well. 1849 01:29:42,616 --> 01:29:44,281 And I'll just give you a taste for this. 1850 01:29:44,281 --> 01:29:46,410 No need to worry about all the specific syntax. 1851 01:29:46,410 --> 01:29:49,368 But just to give you a sense for what's possible with these animations, 1852 01:29:49,368 --> 01:29:52,030 and we'll see where we can go from there. 1853 01:29:52,030 --> 01:29:56,820 So let's take a look now at circle3.html. 1854 01:29:56,820 --> 01:30:00,690 So in circle3.html, we're also going to start 1855 01:30:00,690 --> 01:30:05,250 by adding a circle to our svg element, giving it an x and y-coordinate, 1856 01:30:05,250 --> 01:30:08,820 giving it a radius of 50, filling it in as blue, same as before, 1857 01:30:08,820 --> 01:30:12,480 and saving all of that inside of a variable called c. 1858 01:30:12,480 --> 01:30:15,450 Then down here, we're going to apply a transition to it. 1859 01:30:15,450 --> 01:30:18,400 It's going to last one second and .delay says, 1860 01:30:18,400 --> 01:30:20,650 how long should you wait before during the transition? 1861 01:30:20,650 --> 01:30:23,230 So here is one way to put off a transition until later. 1862 01:30:23,230 --> 01:30:26,109 We can say delay it by a second and then run the transition. 1863 01:30:26,109 --> 01:30:28,650 And that transition is just going to change the x-coordinate. 1864 01:30:28,650 --> 01:30:33,010 It's going to move to the right from x-coordinate 200 to x-coordinate 500. 1865 01:30:33,010 --> 01:30:36,840 And in the case of navigating the pixels on the HTML page-- 1866 01:30:36,840 --> 01:30:42,320 00, the origin-- that is the upper-left corner of the HTML page. 1867 01:30:42,320 --> 01:30:45,080 We can also cause transitions to happen, only 1868 01:30:45,080 --> 01:30:47,270 when something is clicked on, for instance, 1869 01:30:47,270 --> 01:30:49,520 like an onclick type event Handler. 1870 01:30:49,520 --> 01:30:51,320 And the way you would write that in D3-- 1871 01:30:51,320 --> 01:30:53,278 and again, this is all syntax you could look up 1872 01:30:53,278 --> 01:30:55,760 on D3's documentation, will just give you a taste for it-- 1873 01:30:55,760 --> 01:31:00,770 is say on click-- in other words, when this button c is clicked on-- 1874 01:31:00,770 --> 01:31:02,960 run this function. 1875 01:31:02,960 --> 01:31:07,940 d3.select this is special D3 syntax for get the thing that was clicked on. 1876 01:31:07,940 --> 01:31:09,770 We're going to apply a transition to it. 1877 01:31:09,770 --> 01:31:12,440 That transition is going to last 30 seconds. 1878 01:31:12,440 --> 01:31:14,420 And what's going to happen in that transition, 1879 01:31:14,420 --> 01:31:18,230 we're going to change the fill color of the circle to be red. 1880 01:31:18,230 --> 01:31:21,360 1881 01:31:21,360 --> 01:31:26,330 So if I open up circle3.html, the first thing that happens is after one second, 1882 01:31:26,330 --> 01:31:30,670 the blue circle moves from x-coordinate 200 to x-coordinate 500. 1883 01:31:30,670 --> 01:31:33,920 And then if I click on the blue circle, then over the course of three seconds, 1884 01:31:33,920 --> 01:31:35,750 it changes its color from blue to red. 1885 01:31:35,750 --> 01:31:39,750 I've added this event Handler that allows me to manipulate it in some way. 1886 01:31:39,750 --> 01:31:44,690 And so how can we begin to use this to create potentially a user interface 1887 01:31:44,690 --> 01:31:46,790 that we can actually click on and interact with? 1888 01:31:46,790 --> 01:31:51,150 Well, let's take a look at stoplight.html. 1889 01:31:51,150 --> 01:31:54,770 stoplight.html is going to be inside the body of it. 1890 01:31:54,770 --> 01:31:57,230 All it contains is this svg element. 1891 01:31:57,230 --> 01:32:01,550 All the interesting stuff happens in the JavaScript-- happens in the D3. 1892 01:32:01,550 --> 01:32:06,350 So we first get our svg container where everything is going to go inside, 1893 01:32:06,350 --> 01:32:08,450 and I'm going to add a rectangle first. 1894 01:32:08,450 --> 01:32:10,880 This rectangle is going to have an x and y-coordinate. 1895 01:32:10,880 --> 01:32:13,130 It's going to have a width of 200 and a height of 500, 1896 01:32:13,130 --> 01:32:15,110 so it's going to be taller than it is wide. 1897 01:32:15,110 --> 01:32:17,210 And we're going to fill it in as black. 1898 01:32:17,210 --> 01:32:18,350 And so what I'm going to try and create here 1899 01:32:18,350 --> 01:32:20,058 is create one of those traffic stoplights 1900 01:32:20,058 --> 01:32:24,840 with the red, green, and yellow lights that can go on and off, for instance. 1901 01:32:24,840 --> 01:32:29,980 And we'll try and see if we can animate that using these vector graphics. 1902 01:32:29,980 --> 01:32:33,050 So I'll define a variable called red and that red is going 1903 01:32:33,050 --> 01:32:34,790 to represent the red light circle. 1904 01:32:34,790 --> 01:32:38,110 And so I'm going to go ahead and add a circle to this svg. 1905 01:32:38,110 --> 01:32:41,227 I figured out by just drawing it out where the x and the y-coordinates 1906 01:32:41,227 --> 01:32:42,560 should be, how big it should be. 1907 01:32:42,560 --> 01:32:44,570 And I'm going to start by just filling it in as gray. 1908 01:32:44,570 --> 01:32:46,550 It's not going to be filled in to start with. 1909 01:32:46,550 --> 01:32:50,670 Same thing is going to be true of the yellow and the green light buttons. 1910 01:32:50,670 --> 01:32:53,737 Those are just going to be circles that I add to the svg container. 1911 01:32:53,737 --> 01:32:55,070 They have an x and y-coordinate. 1912 01:32:55,070 --> 01:32:58,670 They all have radius 75, and they're all going to be filled in as gray, 1913 01:32:58,670 --> 01:33:01,070 to begin with. 1914 01:33:01,070 --> 01:33:05,990 Then when the red button is clicked, here's what I'm going to have happen. 1915 01:33:05,990 --> 01:33:09,600 Change the red style to be filled in with the color red. 1916 01:33:09,600 --> 01:33:12,230 That red circle is now going to show up as red. 1917 01:33:12,230 --> 01:33:14,324 And the other two circles-- 1918 01:33:14,324 --> 01:33:15,740 those should be filled in as gray. 1919 01:33:15,740 --> 01:33:16,830 Maybe they were already gray. 1920 01:33:16,830 --> 01:33:17,470 Maybe they weren't. 1921 01:33:17,470 --> 01:33:20,011 But we're going to change their color to gray no matter what. 1922 01:33:20,011 --> 01:33:23,870 And likewise, for the yellow button, when I click on that, 1923 01:33:23,870 --> 01:33:27,380 change the yellow button to be yellow and change the other two to be gray. 1924 01:33:27,380 --> 01:33:30,980 And when the green circle is clicked on, the green circle should now be green, 1925 01:33:30,980 --> 01:33:32,450 and the other two should be gray. 1926 01:33:32,450 --> 01:33:36,890 And so using just this JavaScript code of adding these rectangles and circles 1927 01:33:36,890 --> 01:33:38,840 and defining what happens on click events, 1928 01:33:38,840 --> 01:33:43,307 without any additional work needed, now I want to open up stoplight.html. 1929 01:33:43,307 --> 01:33:44,390 What I get is a stoplight. 1930 01:33:44,390 --> 01:33:46,310 This was the black rectangle that I created, 1931 01:33:46,310 --> 01:33:49,620 and then I added three circles of specific x and y-coordinates. 1932 01:33:49,620 --> 01:33:52,490 And when I click on individual circles here, I click on the red one, 1933 01:33:52,490 --> 01:33:53,545 the red light turns on. 1934 01:33:53,545 --> 01:33:55,920 I click on the next light, now the yellow light turns on, 1935 01:33:55,920 --> 01:33:57,320 and the other two turn gray. 1936 01:33:57,320 --> 01:34:01,610 And I've been able to create a sort of stoplight-like user interface, where 1937 01:34:01,610 --> 01:34:04,274 I can click on something and cause its color to change. 1938 01:34:04,274 --> 01:34:06,690 And just by clicking around, I can manipulate these events 1939 01:34:06,690 --> 01:34:10,880 and manipulate the CSS properties of these individual elements. 1940 01:34:10,880 --> 01:34:14,900 Questions on anything so far for how we're able to build this out? 1941 01:34:14,900 --> 01:34:18,440 And a lot of this is just figuring out how many pixels things should be 1942 01:34:18,440 --> 01:34:20,270 and figuring out how big things should be. 1943 01:34:20,270 --> 01:34:23,103 But this is the general sense for if you want to user interface that 1944 01:34:23,103 --> 01:34:26,270 isn't just buttons and sliders and people typing into text fields, 1945 01:34:26,270 --> 01:34:30,476 you can build whatever user interface you want just by drawing it out 1946 01:34:30,476 --> 01:34:33,350 for yourself, by defining what shapes you want in the user interface, 1947 01:34:33,350 --> 01:34:36,890 and what should happen when you click on various elements. 1948 01:34:36,890 --> 01:34:40,310 All right, so let's try and actually build 1949 01:34:40,310 --> 01:34:44,450 a sort of interesting application using D3, 1950 01:34:44,450 --> 01:34:49,590 using the ability to add lines and circles to our page. 1951 01:34:49,590 --> 01:34:52,010 So what we're going to try and do is create 1952 01:34:52,010 --> 01:34:56,647 an application that allows us to draw on a canvas on the web page. 1953 01:34:56,647 --> 01:34:58,480 Sort of like a whiteboard that lets me draw, 1954 01:34:58,480 --> 01:35:01,770 we're going to get a web page that lets me draw whatever I want. 1955 01:35:01,770 --> 01:35:05,750 So let's go ahead and look at draw0.html. 1956 01:35:05,750 --> 01:35:10,070 So in draw0.html, we have this svg area that's 1957 01:35:10,070 --> 01:35:13,070 just going to be where the vector graphics are going to be stored. 1958 01:35:13,070 --> 01:35:18,600 And inside of the script tags, here's what we have going on. 1959 01:35:18,600 --> 01:35:22,760 So we have a variable called svg, which is just that whole svg container. 1960 01:35:22,760 --> 01:35:25,920 I have this function draw_point, which we'll come back to in just a moment. 1961 01:35:25,920 --> 01:35:27,253 But in particular, look at this. 1962 01:35:27,253 --> 01:35:30,080 At the very bottom, whenever this event happens, 1963 01:35:30,080 --> 01:35:32,870 svg on mouse move-- in other words, whenever 1964 01:35:32,870 --> 01:35:35,900 the mouse moves over the svg canvas, we're 1965 01:35:35,900 --> 01:35:38,780 going to run the draw_point function. 1966 01:35:38,780 --> 01:35:41,101 And so what happens in the draw_point function? 1967 01:35:41,101 --> 01:35:43,100 Well, the first thing I need to do is figure out 1968 01:35:43,100 --> 01:35:45,320 where the mouse is currently, and D3 happens 1969 01:35:45,320 --> 01:35:46,730 to have an easy way to get this. 1970 01:35:46,730 --> 01:35:50,570 We do d3.mouse this, which just gets me the current position 1971 01:35:50,570 --> 01:35:52,567 of the mouse in the svg element. 1972 01:35:52,567 --> 01:35:54,650 And we'll save that in coordinates, which is going 1973 01:35:54,650 --> 01:35:57,470 to be an x position and a y position. 1974 01:35:57,470 --> 01:36:00,140 And now to simulate the idea of drawing. 1975 01:36:00,140 --> 01:36:03,800 Now that I know where the mouse is, let's go ahead and just put a black dot 1976 01:36:03,800 --> 01:36:05,270 right there where the mouse is. 1977 01:36:05,270 --> 01:36:07,852 So we're going to add to this svg a circle, 1978 01:36:07,852 --> 01:36:11,060 setting its x attribute to be whatever the first part of the coordinates are. 1979 01:36:11,060 --> 01:36:14,570 The y attribute is going to be whatever the y part of the coordinates are. 1980 01:36:14,570 --> 01:36:16,070 Radius is going to be 5. 1981 01:36:16,070 --> 01:36:18,080 We're going to fill it in as black. 1982 01:36:18,080 --> 01:36:19,859 And so we've taken our svg element. 1983 01:36:19,859 --> 01:36:21,650 Whenever someone moves their mouse over it, 1984 01:36:21,650 --> 01:36:23,340 we're running the draw_point function. 1985 01:36:23,340 --> 01:36:25,048 The draw_point function figures out where 1986 01:36:25,048 --> 01:36:31,220 the mouse is and adds a small circle, just 5 pixels in radius, 1987 01:36:31,220 --> 01:36:33,070 and it places it there. 1988 01:36:33,070 --> 01:36:39,980 And so when we run that, by opening up draw0.html, what we'll notice 1989 01:36:39,980 --> 01:36:44,285 is that as soon as I start to move this cursor, the mouse is moving. 1990 01:36:44,285 --> 01:36:46,160 And as a result, every time I move the mouse, 1991 01:36:46,160 --> 01:36:48,150 it's putting a little dot right there. 1992 01:36:48,150 --> 01:36:52,640 And if I move the mouse quickly, because the mouse move event is only fired 1993 01:36:52,640 --> 01:36:56,084 every at certain intervals, and it's not continuously fired constantly, 1994 01:36:56,084 --> 01:36:58,500 you'll actually see that you can see these individual dots 1995 01:36:58,500 --> 01:37:00,170 if I start to move them more quickly. 1996 01:37:00,170 --> 01:37:02,630 That each time this mouse move event is fired, 1997 01:37:02,630 --> 01:37:04,687 it's just going to drop a dot right there. 1998 01:37:04,687 --> 01:37:06,770 And the result is that I sort of have this ability 1999 01:37:06,770 --> 01:37:11,659 to paint whatever I want just by moving the mouse around. 2000 01:37:11,659 --> 01:37:13,700 Questions about how I was able to make that work? 2001 01:37:13,700 --> 01:37:16,440 2002 01:37:16,440 --> 01:37:17,830 OK, so this is nice. 2003 01:37:17,830 --> 01:37:19,600 Let's try and make some incremental improvements of this. 2004 01:37:19,600 --> 01:37:21,600 Figure out what code we need to change, what events 2005 01:37:21,600 --> 01:37:23,130 we need to change to make it better. 2006 01:37:23,130 --> 01:37:27,429 One thing that's immediately obvious is that I have no way to stop drawing. 2007 01:37:27,429 --> 01:37:28,470 I'm just moving my mouse. 2008 01:37:28,470 --> 01:37:29,553 I'm not clicking anything. 2009 01:37:29,553 --> 01:37:32,040 But whenever the mouse is moving over the svg container, 2010 01:37:32,040 --> 01:37:33,420 it's drawing right there. 2011 01:37:33,420 --> 01:37:37,410 So what I might like to do is make it so that I need to click and drag 2012 01:37:37,410 --> 01:37:38,850 in order to actually draw a line. 2013 01:37:38,850 --> 01:37:41,650 If I'm not clicking, then it's not going to do anything. 2014 01:37:41,650 --> 01:37:47,850 So any thoughts as to intuitively or instinctively what might 2015 01:37:47,850 --> 01:37:55,140 I need in order you get the idea of only drawing when I'm clicking and holding 2016 01:37:55,140 --> 01:37:57,060 as opposed to just always? 2017 01:37:57,060 --> 01:38:01,060 Recognizing that I have this mouse move event, but I've been using already. 2018 01:38:01,060 --> 01:38:02,134 Yeah? 2019 01:38:02,134 --> 01:38:03,060 AUDIENCE: [INAUDIBLE] 2020 01:38:03,060 --> 01:38:04,810 BRIAN YU: Yeah, so we can look for events 2021 01:38:04,810 --> 01:38:08,410 of when the mouse or when we click down on the trackpad or on the mouse 2022 01:38:08,410 --> 01:38:10,930 and when we click up and do something interesting there. 2023 01:38:10,930 --> 01:38:14,800 So let's take a look at what one example of what we might do. 2024 01:38:14,800 --> 01:38:17,490 So here we have a very simple thing going on, 2025 01:38:17,490 --> 01:38:20,130 where this is similar to the prior example, 2026 01:38:20,130 --> 01:38:22,840 except I've added a Boolean variable called drawing. 2027 01:38:22,840 --> 01:38:25,590 It's just going to keep track of whether or not we should actually 2028 01:38:25,590 --> 01:38:26,940 be drawing right now. 2029 01:38:26,940 --> 01:38:29,770 And by default, drawing is going to be false. 2030 01:38:29,770 --> 01:38:33,940 And inside of this draw_point function, if drawing is false-- 2031 01:38:33,940 --> 01:38:36,210 in other words, if we shouldn't be drawing right now-- 2032 01:38:36,210 --> 01:38:39,726 then return out of this function-- don't do anything. 2033 01:38:39,726 --> 01:38:42,850 But otherwise, if we should be drawing, then go ahead and do the same thing 2034 01:38:42,850 --> 01:38:43,433 we did before. 2035 01:38:43,433 --> 01:38:47,110 Go ahead and drop a point right there. 2036 01:38:47,110 --> 01:38:49,692 Then at the bottom, here are these event handlers. 2037 01:38:49,692 --> 01:38:52,900 Whenever the mouse moves, we're still going to call that draw_point function. 2038 01:38:52,900 --> 01:38:55,640 But now we need to make sure that the drawing variable is 2039 01:38:55,640 --> 01:38:57,640 set to the right value, true or false, depending 2040 01:38:57,640 --> 01:38:59,150 on what's currently happening. 2041 01:38:59,150 --> 01:39:02,890 And so what I'm going to say is on the mousedown event-- when I click down-- 2042 01:39:02,890 --> 01:39:05,427 go ahead and set the drawing variable to true. 2043 01:39:05,427 --> 01:39:07,760 And when I click the mouse up-- when I'm done clicking-- 2044 01:39:07,760 --> 01:39:10,150 set the drawing variable to false. 2045 01:39:10,150 --> 01:39:12,944 That way, if I click down, drawing is now true. 2046 01:39:12,944 --> 01:39:15,610 Now when I move the mouse, drawing is true as I draw the points. 2047 01:39:15,610 --> 01:39:16,940 So it's going to draw the line. 2048 01:39:16,940 --> 01:39:19,630 But as soon as the mouse comes up, drawing is now set to false. 2049 01:39:19,630 --> 01:39:21,421 So even though I'm going to move the mouse, 2050 01:39:21,421 --> 01:39:23,320 and the draw_point function will be called, 2051 01:39:23,320 --> 01:39:28,630 I'm not actually going to see any points getting placed onto my svg canvas. 2052 01:39:28,630 --> 01:39:35,870 And so the result of that is that if I open draw1.html, 2053 01:39:35,870 --> 01:39:38,742 I can move the mouse around over the canvas now and nothing happens. 2054 01:39:38,742 --> 01:39:41,200 But it's not until I actually click down and actually start 2055 01:39:41,200 --> 01:39:45,170 drawing that I get these lines here. 2056 01:39:45,170 --> 01:39:48,072 And so again, if I move the mouse more quickly, 2057 01:39:48,072 --> 01:39:50,780 then you start to see that these lines aren't actually connected. 2058 01:39:50,780 --> 01:39:52,360 And so this isn't ideal. 2059 01:39:52,360 --> 01:39:56,500 And there's not a ton that we can do in terms of addressing this 2060 01:39:56,500 --> 01:40:00,190 because we can't actually change the frequency at which the mouse move 2061 01:40:00,190 --> 01:40:00,910 event is fired. 2062 01:40:00,910 --> 01:40:02,830 The mouse move event is fired by the browser, 2063 01:40:02,830 --> 01:40:05,720 and so we don't really have control over that. 2064 01:40:05,720 --> 01:40:07,510 So what might be a good heuristic that we 2065 01:40:07,510 --> 01:40:10,730 could use to sort of solve this problem from a UI standpoint of, 2066 01:40:10,730 --> 01:40:13,090 if I move the mouse quickly, now suddenly 2067 01:40:13,090 --> 01:40:17,128 I get all these individual points, as opposed to a smooth connection? 2068 01:40:17,128 --> 01:40:18,046 Yeah? 2069 01:40:18,046 --> 01:40:20,899 AUDIENCE: Store the previous point [INAUDIBLE] 2070 01:40:20,899 --> 01:40:22,190 BRIAN YU: Yeah, excellent idea. 2071 01:40:22,190 --> 01:40:25,370 So we can store the previous point and then draw a line between them. 2072 01:40:25,370 --> 01:40:28,490 So that's what we are going to do, such that whenever 2073 01:40:28,490 --> 01:40:30,450 we have two points that are next to each other, 2074 01:40:30,450 --> 01:40:32,972 and we're trying to connect them, since we know that there's 2075 01:40:32,972 --> 01:40:35,180 a possibility that there might be a gap between them, 2076 01:40:35,180 --> 01:40:36,736 let's just connect them by a line. 2077 01:40:36,736 --> 01:40:39,860 It might not be perfect, but it will at least give a sort of a better sense 2078 01:40:39,860 --> 01:40:41,900 that we're actually drawing on this canvas. 2079 01:40:41,900 --> 01:40:44,540 And so as our final example, let's take a look 2080 01:40:44,540 --> 01:40:48,920 at draw2.html, which is going to be our most sophisticated application yet 2081 01:40:48,920 --> 01:40:51,920 using D3 and JavaScript. 2082 01:40:51,920 --> 01:40:54,570 And it's going to have a bunch more options. 2083 01:40:54,570 --> 01:40:57,800 So inside the body of this HTML page, we have a heading. 2084 01:40:57,800 --> 01:41:00,390 We're just going to call it E-33a draw. 2085 01:41:00,390 --> 01:41:04,490 And I also have a bunch of these select dropdowns now. 2086 01:41:04,490 --> 01:41:08,210 I'm going to allow myself to be a little more flexible from the user experience 2087 01:41:08,210 --> 01:41:11,060 perspective of being able to choose what color I want to draw in 2088 01:41:11,060 --> 01:41:14,820 and how thick I want the thickness of my brush stroke to be, for instance. 2089 01:41:14,820 --> 01:41:17,570 And so this select, which is just going to be called color-picker, 2090 01:41:17,570 --> 01:41:18,840 has a whole bunch of options. 2091 01:41:18,840 --> 01:41:21,381 Option black, red, blue, green-- here are the possible colors 2092 01:41:21,381 --> 01:41:22,580 that you can draw in. 2093 01:41:22,580 --> 01:41:25,220 And here's a select dropdown, called the thickness-picker, 2094 01:41:25,220 --> 01:41:26,960 where I have a whole bunch of different thicknesses. 2095 01:41:26,960 --> 01:41:29,335 We're going to default to selecting a thickness of three, 2096 01:41:29,335 --> 01:41:35,150 but you could select anything up until thickness 10, in fact. 2097 01:41:35,150 --> 01:41:38,720 And I also have a button called Erase, which will presumably 2098 01:41:38,720 --> 01:41:41,210 erase everything that's on the screen. 2099 01:41:41,210 --> 01:41:45,710 So I'm giving myself more options now by letting the user choose how 2100 01:41:45,710 --> 01:41:47,460 they want to go about drawing things. 2101 01:41:47,460 --> 01:41:49,760 So what's the code that's needed to make this work? 2102 01:41:49,760 --> 01:41:52,390 Well, all of it is going to be inside of draw2.js. 2103 01:41:52,390 --> 01:41:54,459 I've separated it into a separate JavaScript file 2104 01:41:54,459 --> 01:41:56,750 just for the sake of keeping things in different places 2105 01:41:56,750 --> 01:41:59,780 because our HTML file is starting to get a little more complicated, 2106 01:41:59,780 --> 01:42:02,900 and it's often cleaner just to keep things separate. 2107 01:42:02,900 --> 01:42:05,680 So let's look at draw2.js. 2108 01:42:05,680 --> 01:42:07,730 When the DOM finishes loading, we're going 2109 01:42:07,730 --> 01:42:09,505 to keep this Boolean variable, draw, which 2110 01:42:09,505 --> 01:42:11,130 is going to be false to start out with. 2111 01:42:11,130 --> 01:42:14,660 Same as before-- this is keeping track of should we be drawing now or not? 2112 01:42:14,660 --> 01:42:18,710 Or equivalently, is the mouse currently down or not? 2113 01:42:18,710 --> 01:42:22,472 We'll keep track of two arrays-- an array of points and an array of lines 2114 01:42:22,472 --> 01:42:24,930 because our lines are going to connect our points together. 2115 01:42:24,930 --> 01:42:26,638 And we need to keep track of both of them 2116 01:42:26,638 --> 01:42:29,104 because when we later go to erase the entire thing, 2117 01:42:29,104 --> 01:42:31,020 we want to make sure we get rid of everything. 2118 01:42:31,020 --> 01:42:33,470 So we need to keep track of everything we've created. 2119 01:42:33,470 --> 01:42:38,910 And when we render the page-- 2120 01:42:38,910 --> 01:42:41,570 and render is the first thing that we're going to do-- 2121 01:42:41,570 --> 01:42:44,270 we're going to go ahead and add these events. 2122 01:42:44,270 --> 01:42:50,480 So whenever I mouse down, whenever I click down, here's what should happen. 2123 01:42:50,480 --> 01:42:52,350 Set this draw variable to true-- 2124 01:42:52,350 --> 01:42:54,590 because now I want to actually be drawing this-- 2125 01:42:54,590 --> 01:42:59,300 figure out what coordinates I'm at, and then call this draw_point function. 2126 01:42:59,300 --> 01:43:02,587 And draw_point, unlike last time, is going to take three arguments. 2127 01:43:02,587 --> 01:43:05,420 The first argument is going to be the x-coordinate, where I actually 2128 01:43:05,420 --> 01:43:06,470 draw a point. 2129 01:43:06,470 --> 01:43:09,020 The second argument is going to be the y-coordinate of where 2130 01:43:09,020 --> 01:43:10,550 to draw the point. 2131 01:43:10,550 --> 01:43:13,700 And the third argument is going to be a Boolean variable indicating 2132 01:43:13,700 --> 01:43:18,290 whether or not I should also draw a line connecting it to the previous point. 2133 01:43:18,290 --> 01:43:20,540 So when the mouse goes down for the first time, 2134 01:43:20,540 --> 01:43:23,384 I want to draw a point where the mouse went down. 2135 01:43:23,384 --> 01:43:25,550 But I don't want to connect it to any previous point 2136 01:43:25,550 --> 01:43:27,591 because this is the first point that I'm drawing. 2137 01:43:27,591 --> 01:43:29,960 There's nothing to connect it to. 2138 01:43:29,960 --> 01:43:32,180 Meanwhile, when the mouse goes up, we're going 2139 01:43:32,180 --> 01:43:34,490 to get the draw variable to false. 2140 01:43:34,490 --> 01:43:38,210 And when the mouse is moved, if we're not drawing, return-- 2141 01:43:38,210 --> 01:43:39,830 just exit out of this. 2142 01:43:39,830 --> 01:43:42,410 Get the coordinates and then draw the point 2143 01:43:42,410 --> 01:43:44,420 at the x-coordinate and the y-coordinate. 2144 01:43:44,420 --> 01:43:47,120 But go ahead and set this third variable to true, 2145 01:43:47,120 --> 01:43:50,000 meaning I actually want to connect this new point 2146 01:43:50,000 --> 01:43:55,310 to the prior point with some sort of line, as was suggested before. 2147 01:43:55,310 --> 01:43:58,770 This is what happens when the Erase button is clicked. 2148 01:43:58,770 --> 01:44:02,210 We're going to go ahead and loop over all of the points and remove each one. 2149 01:44:02,210 --> 01:44:05,180 Loop over all of the lines and remove each one. 2150 01:44:05,180 --> 01:44:09,340 And then set both points and lines to just be empty arrays. 2151 01:44:09,340 --> 01:44:13,840 And finally, how do we actually draw a point? 2152 01:44:13,840 --> 01:44:16,440 Well, the first thing we're going to want to do 2153 01:44:16,440 --> 01:44:19,850 is figure out the color and the thickness that we want to use. 2154 01:44:19,850 --> 01:44:22,420 So I can get at the color-picker's value, 2155 01:44:22,420 --> 01:44:24,610 save it inside of a variable called color. 2156 01:44:24,610 --> 01:44:26,597 Get at the thickness-picker's value, save it 2157 01:44:26,597 --> 01:44:28,180 inside of a variable called thickness. 2158 01:44:28,180 --> 01:44:31,130 Those were the two dropdowns that we were using before. 2159 01:44:31,130 --> 01:44:35,800 And now recall that draw_point takes in three arguments x, y, 2160 01:44:35,800 --> 01:44:39,070 and connect, where connect is a Boolean of should we connect this 2161 01:44:39,070 --> 01:44:41,080 to the prior point or not? 2162 01:44:41,080 --> 01:44:43,900 And if we should connect this to the prior point, 2163 01:44:43,900 --> 01:44:47,110 then we're going to get the most recent point, which 2164 01:44:47,110 --> 01:44:51,520 is just the last element in this array of points that we have, 2165 01:44:51,520 --> 01:44:55,070 and we're going to create a line that's going to connect those points. 2166 01:44:55,070 --> 01:44:59,500 And so the starting x and y-coordinates of this line 2167 01:44:59,500 --> 01:45:02,710 are going to be the x and y-coordinates of the last point, 2168 01:45:02,710 --> 01:45:08,140 and the line is going to end at the x and y-coordinates of our new point. 2169 01:45:08,140 --> 01:45:12,100 And we're going to add that line to an array of lines. 2170 01:45:12,100 --> 01:45:15,080 Then finally, over here, we're actually going to add the point. 2171 01:45:15,080 --> 01:45:16,480 So we're going to add a circle. 2172 01:45:16,480 --> 01:45:17,830 It's going have x and y center. 2173 01:45:17,830 --> 01:45:20,746 It's going to have this particular thickness and this particular color 2174 01:45:20,746 --> 01:45:23,009 that was whatever the user selected in that dropdown. 2175 01:45:23,009 --> 01:45:25,300 And then we're going to add that to our array of points 2176 01:45:25,300 --> 01:45:27,880 as well so that we can keep track of all of them. 2177 01:45:27,880 --> 01:45:31,540 Then we make sure that we actually do the rendering that causes everything 2178 01:45:31,540 --> 01:45:32,350 to render. 2179 01:45:32,350 --> 01:45:33,836 And the result of all of that-- 2180 01:45:33,836 --> 01:45:35,960 and you can take a look at the source code example. 2181 01:45:35,960 --> 01:45:37,950 It's posted on the course's website-- 2182 01:45:37,950 --> 01:45:42,550 is that if I open up draw2.html, I get a nice heading. 2183 01:45:42,550 --> 01:45:45,550 Right now, I'm on color black and thickness 3, 2184 01:45:45,550 --> 01:45:46,990 and I have this Erase button. 2185 01:45:46,990 --> 01:45:49,636 And now when I start drawing, even if I move it quickly 2186 01:45:49,636 --> 01:45:51,260 it's still going to connect everything. 2187 01:45:51,260 --> 01:45:53,385 And if I move things very quickly, you can actually 2188 01:45:53,385 --> 01:45:56,530 see that there are lines that are connecting these individual points. 2189 01:45:56,530 --> 01:46:00,010 But I can also change the color and the thickness. 2190 01:46:00,010 --> 01:46:02,950 And that causes things to be painted in a different color, 2191 01:46:02,950 --> 01:46:05,590 different thickness-- 2192 01:46:05,590 --> 01:46:08,740 changed again. 2193 01:46:08,740 --> 01:46:10,780 And likewise, whenever I press the Erase button, 2194 01:46:10,780 --> 01:46:13,120 that takes all of the points, all of the lines, 2195 01:46:13,120 --> 01:46:14,930 and just causes them all to disappear. 2196 01:46:14,930 --> 01:46:18,070 So I'm left with a fresh canvas that I can continue to draw. 2197 01:46:18,070 --> 01:46:23,730 And so all of that was made possible by using svg's vector graphics, 2198 01:46:23,730 --> 01:46:26,620 where I can add points and lines and have them respond to events-- 2199 01:46:26,620 --> 01:46:29,440 have them respond to people clicking on things, dragging on things, 2200 01:46:29,440 --> 01:46:31,360 mouse down events, mouse up events. 2201 01:46:31,360 --> 01:46:33,790 But all of that, ultimately, is what allows 2202 01:46:33,790 --> 01:46:36,922 me to build what seems to be a pretty functional application for drawing 2203 01:46:36,922 --> 01:46:39,130 things in different colors and different thicknesses. 2204 01:46:39,130 --> 01:46:41,110 Questions about any of that? 2205 01:46:41,110 --> 01:46:44,080 2206 01:46:44,080 --> 01:46:46,551 OK, so that sort of concludes our look into JavaScript. 2207 01:46:46,551 --> 01:46:48,300 Starting next week, we'll take a look back 2208 01:46:48,300 --> 01:46:51,840 at the back-end looking at Python again, moving away from Flask 2209 01:46:51,840 --> 01:46:54,420 and moving into a different web framework, known as Django, 2210 01:46:54,420 --> 01:46:57,003 which is a little more powerful, and we'll see what it can do. 2211 01:46:57,003 --> 01:47:01,320 But that's it for front-ends for today and have a great day. 2212 01:47:01,320 --> 01:47:03,079