User Interfaces - Lecture 6 - CS50's Web Programming with Python and JavaScript 2020

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] welcome back everyone to web programming with python and javascript and last time we took a look at javascript that language that ran inside of a user's web browser client side and allowed us to do a number of things to make our web pages more interactive javascript enabled us to display alerts to be able to manipulate the dom the structure of the web page in order to add content or see what content was already there and it also let us respond to user events when a user clicked on a button or submitted a form or typed something into an input field we could have javascript functions run that responded to those events in order to make our web pages more interactive today we're going to continue that conversation in particular taking a look at user interface design looking at some common paradigms in terms of user interfaces and how we can leverage javascript to be able to achieve those goals to create interactive user interfaces that will be valuable when users are interacting with our applications so one of the more common paradigms especially nowadays in web programming is the idea of single page applications thus far if we wanted to create a web application that has multiple different pages we've generally done that via multiple different routes in our django web application for example where you go to slash something to get one page and slash something else in order to get another page but commonly using javascript we have the ability to create single page applications where the entire web page is really just a single page and then we use javascript to manipulate the dom to replace portions of the page with things we want to replace and this has a number of advantages one of them being that we only need to make modifications to the part of the page that is actually changing if for example you have five different pages but the general layout and structure of the page is pretty similar when you switch between pages rather than load an entirely new page you can just load the part of the page that is changing and this is especially helpful for applications that are changing quite frequently so let's take a look now at how we could implement for example a very simple single page application so let's imagine for example that we want a single page application that just displays three different pages but all included in the same page i'll go ahead and create a new file that i'll call singlepage.html inside of which we'll include our usual html tags and inside the body of this page now i'm going to include three different sections of the page to represent the three different pages i might want to display to the user so i'll have a div whose id is page one that maybe just has a heading that says this is page one and you could imagine there's more content on these pages as well a div whose id is page two we'll say this is page two and then one final div whose id is page three it has a heading that says this is page three for example now right now if i were to open up single page.html what we'd see is we see all three pages at the same time and now that's probably not what we want what we really want is by default to hide these pages until we want to view the pages one at a time for example so one thing i could do is use css to be able to toggle whether or not something is visible adding some style tags to my page to say that by default all of my divs should have a display property set to none meaning they're not visible they're not displayed on the screen now if i refresh the page i don't actually see any of the three headings that i had there before but what i'd really like is for some buttons now to allow me to toggle between these three pages so i'll give myself three buttons one button that says page one one button that says page two and one button that says page three for example and i need some mechanism for these buttons to know when you click on this button what page should be displayed so i'll go ahead and use data attributes which we saw last time with javascript to add some additional information to these particular html elements where i'll give the first button a data dash page value of page one the second one a data dash page value of page two and the third one a data dash page value of page three here again just providing information so that later when i write some javascript i can have the javascript code look at the data dash page attribute to say that when you click on this button you should let me see the div whose id is page one that's what this is going to allow us to signal so now let's go ahead and write that javascript what i want to be able to do is to be able to say i would like to show page one and hide the other two or show page two and hide the other two or show page three for example and so to do that i'll first write a function that will let me do that i'll write a function called show page that takes as its argument like what page i want to show and so what should this function do what we're going to do is we're going to say document.queryselector and i want to get the thing that has a particular id the id of whatever this input happens to be this page is going to represent the id of the div that i want to show so i'll say get me the thing that has this id and then using a template literal i'll say all right get me the id of page whatever element has that particular id and then i'd like to change its style property which part of the style well i want to change its display property and instead of none which was the default here where i said don't show it at all the other option for a div is block meaning it shows up as just a block that is on the page that is actually visible and so now i have this show page function and i can test it in fact if i go into my browser refresh the page i now see three buttons the buttons don't do anything just yet but what i can do is in the console if i actually just try running this i can run the show page function and say like show page page one for example press return and all right page one now appears on my page and if i rest show page page two then page two will become visible and all right that did half of what i wanted page two is now visible but so is page one so i probably want it such that if i ever show a page i hide the other pages first like hide all the pages and then show page two or hide all the pages and then show page three so how could i go about doing that well first i might want to just when i show a page first hide all of the other pages hide all the pages so to get all the pages i'll do document.query selector all get all of the divs which is what i'm using to include enclose the pages and now for each one of those again effectively creating a loop where i'm looping over each of the divs for each div let's go ahead and set the div dot style dot display property equal to none and so what this show page function is now doing is it is first querying for all of the divs which are simulating my pages inside of the single page application and for each one of the divs we're going to pass it as input into this function which is the argument to for each again using this arrow function notation which is just a shorthand way of expressing a function where i'm here saying that for each of the divs we'll go ahead and modify its style property setting display equal to none meaning don't show any of the divs and then show only the div that was requested so now this should solve the problem of multiple pages appearing simultaneously that if i go back to this page and i click or write show page page one then page one appears but if i run show page of page two then page two appears but page one disappears and likewise when i show page page three that shows page three but not the other two so i can manipulate which page is visible all via the console but now what i'd like to do is get these buttons to actually work where if i click on one of the buttons that has the effect of actually displaying the requested page so in order to do that well i want to attach some event listeners to these buttons which means i need to wait until those buttons have loaded onto the page so we'll use document dot add event listener dom content loaded again waiting until all of the content on the page has been loaded and then and only then will i say let's go ahead and query selector all for all of the buttons and for each one of those buttons let's go ahead and attach an event listener to each of those buttons so i'm querying for all of the buttons and saying for each of the buttons i would like to do this with each button and what i'd like to do is say button.onclick when the button is clicked on go ahead and run this function i'd like to show page and which page do i want to show well i want to show whatever page is in the page part of the button's data set and to get it the current button the button that has been clicked on recall that when we're inside of an event handler we can take advantage of the javascript keyword this which refers to whatever element has received the event so whatever button in this case that was clicked on so i can say this dot dataset dot page to mean that all right for each of the buttons when the button is clicked on we're saying button.unclick for each of the buttons run this function when the button is clicked we'd like to show a page which page do we want to show we'll take this button the button that received the event access its data properties accesses data page attribute which are down here either page one or page two or page three and go ahead and just call the show page function that we wrote a moment ago so now that we've done that we've attached these event handlers to the buttons so now if i refresh the page i can click on these buttons and toggle between any of the three pages and now the interesting thing here is that we now have the ability to just in a single page allow myself to simulate the idea of having multiple pages all enclosed in a single html file but not needing to consistently make additional requests to a server in order to get access to that information now sometimes though it might be reasonable to want to reach out to a server when you need new information for a page for example you might imagine that each of these pages contains a lot of text it's going to be inefficient if immediately we're loading all of that data into html and just showing and hiding them when we need to because maybe we're loading more information than the user is ever going to actually care about if they're never going to look at page 2 or page 3. so one thing we might imagine doing is loading this data dynamically last time when we were talking about javascript we saw how we could use fetch to say go ahead and request some additional information from a web server last time it was currency exchange rates but then we used that data that came back in order to fill in something onto our page and likewise we could do a similar thing here that if we have the general structure of a single page and we want to load new content rather than load entirely new html content and reload the entire page we can just ask our own web server for what part of the page needs to change and then just replace that part of the page and so that's what we'll take a look at now now combining django for our web server and javascript for writing the client side code to be able to generate a single page application and so for this we'll go ahead and go into an example i had in advance called single page one and inside of single page one this is just a django application with a single app called single page and what we'll notice is we'll go to the urls first there are two urls one default url that just loads the index function and then a url for loading different like sections of a page that i might want to dynamically load for example so i have section slash some particular number and if we look at the views for what it is these urls are actually doing the index function just returns index.html and then what the section function does is it first makes sure the number is between one and three and if so responds with one of these just strings of text for example so how does this actually work if i go into single page one and run the server if i go to this url slash section slash one for example what i get is this block of text and if i go to slash section slash two i get that block of text section slash three a different block of text altogether so just different text and i'd like to incorporate this text into an existing html page for instance so here i'll go into index.html this template that gets loaded when i go to the default route and inside of index.html what we'll see is i have a show section function that behaves very similar to the show page function we saw from a moment ago but instead what show section is going to do is it's going to fetch what text i should display on the page from my own web server i'm fetching from slash sections slash fill in a number here number like one or two or three when i get the response in the past we've seen how we can convert that response into json data if it's some structured data we can also just convert the response into plain text then i'll take that text console.log it just so we can see it in the log output but then go ahead and query select for the content of the page something that has an id of content update its innerhtml and set it equal to that text so what this entire function is now doing is it is going to reach out to my server figure out what text content belongs in the new section and fill in the part of my page accordingly with the text that comes back from that http request and then down further below inside of the page we'll see that i have a hello heading three buttons that toggle between the different sec sections each of them has a data dash section attribute this time for which section should be loaded and then a div that is initially blank just for the content of the page so putting this all together now if i go to the default route i see hello plus three buttons to give me a choice between three different sections and if i click section one what's going to happen is javascript is going to query section slash one ask for the text it gets that text back and it's going to fill it in into the page section one section two and section three so very similar to before but unlike what we had before where all of the text was being loaded into the html page all at once now we're using asynchronous javascript to only dynamically load information when we need it when we click on a section then it's going to make the request for what content needs to be filled in and it's going to fill it in and everything else these buttons this heading and you might imagine in a more complex website you've got a lot more going on around the edges of this webpage all of that stays the same we don't need to reload any of that information we're only reloading the portion of the page that actually changes as we toggle between these various different section headings now this seems to be an advantage in some ways that maybe we can be more efficient about how we run our single page applications like this one thing we seem to lose though is the notion of maintaining state inside of the url that generally the url gives you an indication for what page you're on you're on something like slash one if you're on section one or slash two if you're on section 2 3 for section 3 but of course we're staying on the same page in all of these examples whenever i click a button section 1 or 2 or 3 the url is never changing the url stays the same it turns out there's a way in javascript to manipulate that url taking advantage of what's known as the javascript history api where i can push something to the history meaning update the url and actually save that inside the user's browser history so later on they could potentially go back to that and to do that i'll show you yet another example inside of single page two which is very similar except inside of index.html i've added a couple additional things one is that when i click on a button meaning when i click on section one or section two or section three i've added this line here history.push state what history.push date is going to do is it is going to basically add a new element to my browsing history where i first specify any data associated with the state so in particular i'm storing a javascript object representing what section number is being represented here next is a title parameter that most web browsers actually ignore so that can generally be the empty string but the third argument here is what should go in the url and what i want to go in the url in this case is something like section followed by the section number so i can go to slash section one or slash section two or slash section three for instance and those will appear in the url bar when i click on a different page then what i want to be able to support is the ability to say when i go back through my history if i click the back button in my web browser i'd like to go back from section 3 to section 2 if that was the page i visited previously and there turns out to be an event handler for that as well window.onpopstate meaning when i pop something off of the history like go back in my history we have the ability to take some event as an argument and if you look at event.state.section which i've run console.log on so we can take a look at it in a moment we'll see what state was stored associated with that part of the user's history and i can go ahead and show that section so all in all when i run this web application going into single page two this time when i run the server i see hello three sections for buttons when i click on one of those buttons not only do i see text but i also see in the url bar that i'm now on slash section one that has been pushed onto my history and i've updated the url to reflect that too i click section two that updates the url as well section three updates the url too and when i've pushed things onto my history i've associated some state with them so that i can go back if i ever need to and in fact if i open up the javascript console now and i go back for example back to section two what you'll see is that what gets logged is the number two when i print out like what is the current section that's associated with this url it's saving that state that i should be loading section number two and so it does load section number two here so there's certainly nothing wrong with the original paradigm of just loading different pages dynamically using django like make a request and get a response but oftentimes as you begin to imagine applications where a lot of things are changing on the same page simultaneously you might imagine social networking websites where a lot of things stay the same but new posts might be added and you might be looking at different parts of the same page being able to dynamically load information request additional information and then display it on the page can actually be quite powerful a way to make your web pages a little bit more interactive so that then is how we might build single page applications taking advantage of javascript to asynchronously load new data and then taking advantage of this history api that let us add things to the url add things to the user's browsing history such that we could go back to them later by listening for window.onpopstate and it turns out that window object that we get access to in javascript is quite powerful it represents the physical window on the computer screen that displays all of their web content and there are certain properties of that window we can look at that allow us to enable some interesting features so for example your window is really described by what the user actually sees inside of their window in google chrome or safari or whatever web browser they happen to be using and there are a couple of properties that might be of use something like window.inner with will represent how wide is the window which might be useful to know to know like the size of the user's screen for example to know how many pixels wide the window happens to be and just as there's a window.inner width there's also a window.inner height that represents the height of the window as well now window represents the physical part that they're actually seeing we've also seen another variable that javascript gives us access to and that is this document object so what is the difference between the window and the document well the document generally represents the entire web page but if web pages are long oftentimes the web page doesn't fit entirely inside of the window that you generally have to scroll through an entire web page and the window is only showing you one portion of that page in any given time so you can represent the document as like this big vertical section that goes beyond the window there might be part of the document that is above the window part of the document that is below the window as well so window.scroll y is another variable you have access to on the window and window.scrolly represents how many pixels far down have you scrolled so if you're at the top of the page window.scrolly is zero you haven't scrolled at all but as you begin to scroll if you want to know how far the user has scrolled on a page you can look at window.scrolly to figure out the number of pixels the user has scrolled in the y direction the up and down direction and the entire height of the page is represented in document.body.offset height that represents how tall the entire height of the document is and we talk about all this in addition to things like window.inner height and window.inner with because using all of these values together you can begin to do some interesting calculations so one thing you might want to detect for example is has the user scroll down to the bottom of the page or not that might be something you care about knowing and it turns out there isn't an event listener that does this automatically but we can calculate it in order to try and figure this out if inner height is the height of the window scroll y is how far vertically the user has scrolled and document body offset height is the entire height of the document you can ask yourself what needs to be true if the user has scrolled to the bottom of the page and well if the user is scrolled to the bottom of the page well then scroll y plus the inner height meaning the amount they've scrolled plus the height of the window that must be at least or equal to document body offset height meaning the amount that they scrolled plus the window takes you down to the bottom of the page to the end of the page to however tall the document happens to be and using that mathematical comparison we can actually detect when the user has reached the bottom of the page and we can actually try and now put that into practice so i'll go ahead and open up an example that i have here called scroll.html and all scroll.html has right now is 100 paragraphs inside of the body tag i have a p for paragraph paragraph one paragraph two so on and so forth i have 100 paragraphs inside of the body of this html page and that's all that really is there right now such that now if i go ahead and open scroll.html i see that i have 100 paragraphs that i can scroll through and what i might like to do is detect when i've reached the bottom of the page and maybe do something when i do so something like change the color of the page for instance so how might i go about doing that well i'm going to need some javascript so i'm going to add some javascript and i'll add an event listener for window dot on scroll on scrolling is an event that listens for what i'm scrolling through the window and when i scroll through the window we'll go ahead and run this function i'll just use an arrow function as a shorthand here what do i want to calculate well i want to calculate if window dot inner height meaning the height of the window itself plus window.scroll y meaning the amount that i've scrolled if that is at least document.body.offset height well that means i must have scrolled to the bottom of the page or maybe even a little bit further if there's a little wiggle room to scroll past the end of the page so if this is true well then i've reached the end of the page and then we'll go ahead and say document.query selector body and let's go ahead and change its style in particular change its background color and change the background color to green otherwise if we haven't reached the end of the page then we'll take the body of the page and change its background color to white so what we're now doing here is taking advantage of the properties we know of this window object saying when we scroll the window let's check to see if we add this up and at least the height of the entire document we've reached the end of the page go ahead and change the style of the background to the body accordingly otherwise change the background to white or leave it at white if it already is so now if i take a look at this actual html page and reload scroll.html we'll see that the background is initially white but as i scroll down once i reach the bottom we'll see that the page changes to green it's white before i reach the bottom but as soon as i get to the bottom of the page it turns to green and the reason why is because the height of the window height of the window here plus however much i've already scrolled from the top of the page up until now that together is equal to the entire height of the document which means we're able to detect the fact that i've reached the end of the page and as a result we can change the color of the background to green now this in itself is not a particularly practical use of detecting when we scroll to the end of something we probably don't usually care about changing the background color when you reach the end of the page but there actually are real applications and you might imagine this in the context of websites that allow for things like infinite scroll that if you're on a social networking site that has a whole bunch of posts you scroll to the bottom of the list of posts and then it generates the new set of posts as well or you're looking at news articles and you're scrolling through news articles and once you reach the bottom it'll load a whole new set of news articles without you having to go to another page how is it doing that well it's a combination of the same types of ideas that we've been talking about number one the ability to detect when you've reached the end of the page using javascript to detect that you're at the bottom of the page and number two to be able to asynchronously load using javascript load additional content fetch some additional page that has some additional content some additional news articles some additional posts and whatnot and then take that information and manipulate the dom to add that information to the existing web page and that ultimately is what's going to give us this power to be able to support something like infinite scroll so let's now go ahead and try and see what it would look like to implement infinite scroll i've already started to create a sample application inside of this application called scroll and i've got an app called posts inside of it and what the posts app does is it's got a couple of urls it's got a default url that just loads an index row and then a post route that loads this posts view and so let's look at what these do index all it does is going to load a file called index.html this template and if i make a request to slash posts i need to provide two arguments i need to provide a start for what post i want to start with an end for what post i want to end with and then it's just going to generate some sample posts that just say like post number one post number two so on and so forth in practice you could actually use social network posts in place of this but this is good just for demonstration purposes so what this is going to do if i go into uh scroll and run server is that if i go to slash post and say start equals 1 and end equals 10 for example then i get a javascript object that looks like this recall that a javascript object is just a convenient format for passing information back and forth in json format and what we have here is a json object with a key called posts that gives me all of the posts post number one post number two all the way up to number ten and it's giving me those posts because i said start at one end at ten but i could have specified other numbers as well if i had said something like uh start at 20 and go to 28 then it's going to give me post number 20 through post number 28. i can specify the range of posts that i want so this now is an api that i have implemented effectively that allows someone to get access to a variety of different posts by hitting this particular url this endpoint so to speak and passing in parameters passing in what posts they want to start with and what posts they want to end with and then they get all of this data back presented to them in json format that can then be used and what's nice about this is that now when we're loading posts rather than have to just guess at how many posts we need to load and then require someone to go to another page we can just do something like load the first 20 posts and now what we'd like to do is if they reach the end of the page go ahead and load the next 20 posts by hitting this api endpoint getting the next 20 posts and then filling that in into the html page so let's see now how that actually works in practice by taking a look at that template in index.html so go into templates index.html and there's a fair bit of javascript here but look at the body first the body just have a has a div for all the posts that initially is going to be empty now here's what the javascript is going to do and we'll walk through it we start with the first post so counter is going to keep track of what post we need to load next by default we're just going to start by loading post number one we have a variable called quantity that's going to tell us how many posts are we going to load at a time let's just say load 20 posts at a time so start with 1 to 20 then 21 to 40 41 to 60 so on and so forth and when dom content is loaded go ahead and just call this function that's called load and what the load function does is it figures out what the start and end should be it fetches all the new posts uh and then for each of the posts that comes back we is it figures out what the so we're asynchronously asking for new posts and what the ad post function does is it creates a new div populates the post inside of it and adds it to the dom so now that we have these parts the ability to load new posts as by fetching from some url all the posts that we care about and then for each of those posts that comes back add something new to the dom as by creating a new html element and inserting it into the page we have the ability to dynamically load all of these posts so if i go not to slash posts but just to this default route i'll see that we have something like 20 posts that all show up but just 20 posts because every time i call the load function that is going to load the next set of posts for example and so what i can do is in the console if i try running the load function just by calling it myself press return after a second or so the next set of posts show up 21 all the way through 40. i call load again the next set of posts show up 41 through 60. 20 posts at a time all using that asynchronous javascript but now what i'd like to happen is for all this to happen on its own without me having to intervene and manually write javascript calls i would just like to say well the same type of logic as before window done on scroll let's go ahead and say if window.inner height plus window.scroll y is at leastdocument.body.offset height meaning if i have scrolled to the end of the page we'll then just go ahead and call the load function that's all these lines are doing every time i scroll we check did we scroll to the end of the page and if we did scroll to the end of the page then go ahead and load the next set of posts so now i refresh the page i see post 1 all the way up through post 20. now watch what happens when i get to post 20 if i scroll to the bottom after a second the next set of posts appears i scroll to the bottom again i'm at 40 and then after a second the next set appears every time i scroll to the bottom more posts are going to load after that allowing me to effectively implement this idea of infinite scrolling by taking advantage of some javascript techniques where i can check for when i've got to the end of the page and then dynamically do something as a result of that something like load some additional pages onto the screen and so here too a lot of power to be had inside of javascript and a lot of where the power of user interface comes from is from how it is that the user interface interacts with the user thinking about what the user is going to do and how the page should interact as a result something like user scrolls to the end of the page and they see some new pages show up as well and one technique we can use for just making html elements a little more responsive a little bit more interesting is by adding some animation to them as well the ability for things to move around and change their properties in some way and it turns out that css has support for animation css has already given us support for things like styling elements saying we want this element to be of this color and this size for example but it also gives us the ability to animate those properties as well to change the size of something or change the position of something over some amount of time and so let's now take a look at an example of what that might actually look like i'll go ahead and create a new file and i'll call it animate.html and inside of animate.html i'll go ahead and start by including our usual html title is animate and what i'd like to do is just add a little bit of animation using css into this particular page i'm going to start with just a heading a heading that says something like welcome for example it's just going to display a welcome message such that now if i open animate.html here's what i see just a message that says welcome but now let's add some css to it let's go into the style tag and for h1 for this heading i'd like to apply a particular animation to it and i first need to specify what the animation's name is going to be and i can pick a name for the animation i'll say something like grow for example i'll set the animation's duration to be two seconds and then the animation fill mode is like what direction should the animation move in should it go forwards or should it go backwards we'll generally want our animations to go forward so they're making some sort of forward progress according to some rules that we're going to specify so here i'm saying we're going to animate all of our headings using an animation called grow and now i need to define what that animation actually does and to do that up above in style i'm going to say at keyframes grow and what this is going to allow me to do is specify some key frames for this particular element meaning where should the element start what should its style properties be and then at the end what should its style properties be and css is going to take care of the process of figuring out what needs to happen in all those intermediary fractions of seconds for example so what i can say is something like go ahead and grow from meaning what should its initial properties be and maybe initially i want it to have a font size of 20 pixels and then we'll say 2 font size of 100 pixels for example so all in all what this is saying is i would like to apply an animation called grow to all of my headings this animation should last two seconds and go forwards and what is the grow animation going to do well it's going to mean at the start anything that obeys the grow animation we'll start with a font size of 20 pixels and at the end it will grow to a font size of 100 pixels and i have now defined what it is that that animation means so now if i go ahead and refresh this page animate.html you'll see that welcome changes size over the course of two seconds it goes from smaller to larger by obeying those keyframes i told it to obey this particular step a set of instructions where it goes from a particular font size to another font size and as a result we see the effect here on the page and it turns out you can do more than just manipulate size you can manipulate just about any css property you want so if i tell the heading that it should have a relative position meaning its position should be relative to other elements or other things in its parent i can say you should change your position from being zero percent away from the left side of the screen to being 50 of the way from the left side of the screen and at this point grow is probably not the best name for this animation i'll call it move instead so animation name is move and so now what this animation is going to do is it's going to say when you run the animation go from being right next to the left side of the screen to being about 50 away from the left side of the screen so i can go ahead and rerun this and we see that's the animation that takes place it goes from the left all the way back up to about halfway across the screen refresh the page and it goes ahead and does the exact same thing and it turns out we don't just need to specify a beginning point and an endpoint for an animation we can specify various different key frames for different points within the animation that we would like to capture something like at the beginning of the animation have this set of css properties maybe halfway through the animation have a different set of css properties and then at the very end have yet another set of css properties so i could say something like if i want the heading not just to move from left to right but also to move back again i can say at the beginning at the zero percent point when you're zero percent of the way through the animation you should be zero percent away from the left-hand side when you're 50 of the way through the animation you should be 50 away from the left-hand side and then when you're done with the animation 100 of the way through let's go back uh to zero percent away from the left-hand side i now have three keyframes beginning of the animation middle of the animation back to the beginning of the animation again and the effect of this is if i refresh the page we go to the right and then we go back we're able to move one direction and then move back and there are other properties we can use to manipulate these animations as well i can set the animation iteration count for example to 2 to mean rather than just do the animation once and then stop do the animation twice and then stop so i refresh it goes to the right and then it goes left and then it repeats that a second time and it turns out if you really want you can set this to infinite to me never stop performing that animation it's consistently going to have this heading move to the right and then move left according to those key frames that i've specified and so if you ever see things moving around on a page interactive in some way there are a number of ways to do it you can animate things using javascript for example but there are many cases where css alone is pretty good at just creating these types of animations and while this animation right now is just running forever we could use javascript in order to control that animation as well so let's see an example of what that would look like i'll go back here in the body of the page in addition to a heading that says welcome i'll go ahead and add a button that just says click here for example and now what i'll do is add a little bit of javascript i'm going to add some javascript so that the button can now control the animation decide when the animation is going to start and stop and so what we'll do inside of this script is to first say document.addeventlistener dom content loaded meaning wait until the dom is done loading as we've done before and let me now get that h1 element document.queryselector h1 and initially i'm going to set its style.animationplaystate equal to paused so animation playstate is a property of the style that lets me decide if the animation is playing or paused and i can control that using javascript rather than just say run infinitely forever i can say the animation play state should start out as pause by first getting the h1 element then modifying the animation playstate property of that particular element but now what i'd like to happen is anytime someone clicks on the button i want to change the animation playstate so i'm going to say document.queryselector button meaning get that button and when someone clicks on the button let's run this function where if the current animation playstate is paused we'll then go ahead and set animation playstate equal to running and otherwise if it's already running then let's go ahead and set the animation play state equal to paused so all in all what this function is going to do is it's going to get me the heading pause this initially and every time the button is clicked run this function where the function says if we're paused go ahead and start running the animation otherwise go ahead and pause the animation by modifying that animation playstate property of the heading so now if i refresh this page right now we have welcome plus a button that says click here and initially everything is paused there's no animation happening but i click here and that begins the animation which will go on indefinitely until i decide that i want to stop it at which point i click it again and the animation pauses and i can control when to start and when to pause that animation as well and so this can be helpful and nice when you want to create something a little bit more interactive something animated on the page but this is especially helpful because it means that you can gradually change css properties over time rather than just immediately change something you have the ability to animate something to make it work a little bit better so let's take a look at an example of how you might put that idea into practice let's go back to our posts example where we had this infinite scrolling list of posts but imagine now that we want the ability to hide posts when we're done with them so i've prepared an example called hide which is very similar to what we had before but this time i've just added one extra button and the button says hide on every single div right now clicking the hide button does nothing we'll go ahead and implement that in just a moment but first to see how this worked if you go into hide go into the index.html template the only change that's been made here is what happens when i add a new post recall again that what this application does is it loads posts from a server and then when it gets to those posts it goes loops over each of the individual posts which is just a string of text and it adds that string of text inside of an element onto the page via this add post function and what the ad post function is going to do here is first create in a new element create a div in which to store that post give it a class name because that's how we're going to animate it and then set its inner html equal to the contents of the post something like post number one post number two post number three and then add a button that just says hide and then we're going to go ahead and add that to the dom as well so that's what adpost is now going to do we're sort of generating some html using this javascript code and then adding that html to the page and now what we're adding is a div that has not only the contents of the post as text but it's also going to give us access to a button that ultimately we hope is going to let us hide that post as well so how do we actually get the hiding of the post to work well what we want to do is somehow detect when the user clicks on one of those hide buttons so there's a number of ways we could do this but one way is just to listen for any time anyone clicks on the document as a whole anytime anyone clicks on the document i might like to ask something like what did they actually click on and it turns out that with most event listeners the function the event listener takes in can take as an optional argument the event itself which is a javascript object that contains information about the event that happened like the click event or the scroll event or the key down event or the key up event for example and one of the properties you get access to is event dot target which is like what was the target of the event in this case what was the thing that was actually clicked on and i'll go ahead and save event.target inside of a variable called element where the idea now is that whatever gets clicked on that is the events target we're going to save that inside of element and what i want to know is is element is that one of the hide buttons i want to know is it a hide button i could have also attached an event listener to each of the hide buttons this is just an alternative way of doing it that i'm showing you for sake of demonstration where we say when we click anywhere in the document figure out what was clicked on and save it inside of this variable and if it's a hide button then it's going to have a class of hide because i gave every class every hide button a class of hide and so what i can say is if element dot class name equals hide well that means that what was clicked on is something with a class of hide we can assume that it is in fact a hide button and then what i want to do is i can do something like element.remove to say go ahead and get rid of that element so now what does this do if i refresh the page let's try it post number one if i hide it i want to hide post number one all right that didn't quite work it was close it got rid of the hide button but i didn't want to get rid of the hide button i wanted to get rid of the whole post so what's going on here is it seems to be that if the element's class name is hide meaning i clicked on a hide button element.remove just removes that element it removes the hide button but it doesn't remove the post that contains it and if you think about this in terms of the dom the post is a div and its child element is the button this hide button and so you remove the button but it doesn't also remove the post as well if you want to remove the post as well you need to remove not the element but the element's parent and in javascript it turns out there's a way to do that too rather than element.remove i can say element.parentelement.remove to say take the element get its parent and remove that so now i refresh the page now i see post one i want to hide it i hide post one and all right now i see post two and post one has gone away if i want to hide post three i hide post three now post three is gone now i go straight from post two to post four so this works but it's also not immediately obvious what's going on like because all of the posts are the exact same height when i get rid of posts one and three it's not immediately obvious to the eye that they've gone away because post two and four they look almost exactly the same you really have to be paying attention to know that the hiding worked and so this can be a time where animation can actually be quite helpful so what i can do is say something like let's go ahead and give this post an animation associated with every post we'll give it an animation name called hide an animation duration of two seconds we'll say it'll take you two seconds in order to hide uh in an animation fill mode of forwards i want to go forwards with the animation and initially i'll give the post an animation playstate of paused meaning initially i don't want the animation to be running because i don't want to hide all the posts immediately pause this animation later we'll go ahead and run the animation in order to actually hide the post then i need to define what does it actually mean to hide the post and i'll say well all right at the zero percent mark what does it mean let's give yourselves an opacity of one opacity is a css property that just controls how opaque or how transparent an html element happens to be and at the end 100 of the way done with the animation will set opacity to zero so initially we can fully see the element at the end the element is totally transparent and now what i need to do is actually trigger this to happen somehow so this is probably going to happen inside of my event listener where instead of removing the element right away let me just take the parent element and set its animation play state equal to running for example meaning when i click the hide button go ahead and run the animation that will change the opacity from one to zero over the course of a couple of seconds and then if i really want to i can add another event listener to say take the parent element add event listener there's an event called animation end which happens when the animation is over and then i can say all right when the animation is over we'll then go ahead and remove the element so all in all rather than just immediately remove the element when i click on the button that says hide what i'd like to do is say if you click on a button and the button is hide go ahead and get the parent element not the hide button but the post itself set its animation playstate to running meaning run the hide animation and then add an event listener to the parent to that post as a whole to say when the animation is over go ahead and remove that entire post from the dom altogether so what is the effect of all of this now of having this animation and running it well now if i refresh the page i see all these posts if i try and hide like post number two for example you'll see that the opacity changes and then it slowly disappears and then only after it's totally transparent the post disappears entirely so i can say hide post number four it disappears and then post number five jumps up to fill its place and i can do that for any of these posts triggering the animation when i click on the hide button and so this is part of the value of what animation can do is to be able to make our user interfaces a little more pleasant from the perspective of the user by not immediately getting rid of a post but by having a nice fade out so it disappears nicely now even this is not perfect animation wise like one thing you might notice is that it jumps up as soon as the post is gone if i hide post number three i hide it it disappears and post five sort of jumps up very abruptly in order to fill its place what i might like is to be a little bit clever to somehow shrink the size of the post after it's gone so that the post doesn't jump into place but it slides a little bit more naturally into place and so there's some additional things i can play with here maybe i want to say that all right let me make this animation a multiple part animation so here instead of just from zero to a hundred percent setting the opacity from one to zero maybe in the first 75 percent of the animation that will take care of reducing the opacity going down from one all the way down to zero but in the last 25 of the animation will still end with an opacity of zero but anything that creates vertical space i want to reduce down to zero so the height should be zero pixels the line height which is how high the text is should also be zero pixelism any padding i want to go away it turns out i've added some margin to the bottom of the post i want to make that go away as well so i want to set all of those to zero from whatever their initial values happen to be that initially the height is like a hundred percent of what the height could be likewise for line height 100 of the parent initially i have like 20 pixels of padding and a margin at the bottom of 10 pixels and i want all of that to still be true 75 of the way through the animation but it's only in the last 25 percent of the animation that i want to set all of these vertical height properties down to zero i want to remove all the height remove the line height remove all the padding and the effect of this is i'll have an animation now where for the first 75 percent of the animation the only thing that changes is the opacity the opacity goes from one fully visible to zero fully transparent and then in the last 25 of the animation the post is already transparent you can't see it but it's still taking up physical space on the page but we're going to now reduce the height of that post so that now you won't be able to see it at all so now if i refresh this page here again are all the posts but now if i click hide on a particular post we'll see that it first fades out and then its height shrinks so that the next post slides very nicely into place i can do that again hide the post it's transparent and then it slides into place and this again is just an application of this idea of css animations using properties of animation to make our interfaces a little bit nicer to use a little bit clearer visually to the user that one post has gone away and the rest of the posts have now scrolled up in order to take their place so now we've been able to use javascript to create a lot of nice user interfaces we've been able to create single page applications to create infinite scrolling to be able to create some animations as well and use javascript to be able to control them but one thing you might be realizing at this point is that our applications are starting to get fairly complicated there's a lot of javascript code needed to manipulate a lot of different parts of our application at the same time and you can imagine that as web pages start to get more complex and as you want to start making them more interactive and more dynamic there's going to be a lot of javascript code required in order to keep everything in sync in order to make sure that all of the elements are updated when they should so on and so forth and it's for that reason that in recent years a lot of javascript has now turned to some javascript libraries or frameworks that allow to more efficiently and more effectively create user interfaces that are more interactive and more reactive and one of the most popular of these is a framework known as react react is a javascript library that is going to enable us to be able to design user interfaces that are very interactive where the content of the web page updates automatically based on some underlying state and what we'll do now is take a look at a brief taste of react to get a sense for how frameworks like it can actually work and can help us in designing some interactive and useful interfaces for users to be able to interact with react is ultimately based on this idea of declarative programming a particular style of programming which is different from the types of programming you might be familiar with more classical programming styles like imperative programming in imperative programming you generally give the computer commands tell the computer what to do for example if we had that counter program from before and we wanted to update the counter from one number to another number in the view like the html that the user sees we would include something like a heading that just has the number zero inside of it and then the logic in imperative programming would take something like this form it would be like all right first document.queryselector to get that h1 tag get it its innerhtml parseint will take the string and convert it into an integer and we can save that inside of a variable called num for example and then after that if i want to increase it i would take this variable num and just add one to it num plus equals one add one to it and then if i want to update this heading in order to replace the zero with a one for example well then i would need to say document.queryselectorh1 set the inner html equal to that number for instance in order to say all right num is now one go ahead and replace that in the view but this is a fair amount of code to do something fairly simple just like increase a number by one and the reason why is because we've had to be very explicit about what instructions we're giving to the web browser we're saying first grab the h1 figure out what number is inside of it add one to that number and then replace it inside of this tag what declarative program is going to allow us to do is it's going to allow us to just describe what state should be displayed on the page in what form in declarative programming in our view like the html like code that we're going to be writing we're just going to say something like h1 and then in curly braces num to mean like fill in the number here and this is what the react syntax is going to look like and then the logic code if we want to increment that number by one is we just need to say num plus equals one add one to the number and the effect of that is that since we have declared that inside of this heading it should be whatever the value of the number is when we increment the value of number react is effectively just going to update the view so that the number updates as well and so this will be some of the power that react gives us react lets us divide our application into a whole bunch of different components where a component is something like this thing here that is keeping track of some sort of count along with a button that might manipulate it and then make that component based on some underlying state some underlying variables that represent the state of the application something like the current number and then we can manipulate that state and when we manipulate the state that will have an impact on what the user actually sees and react will handle the process of updating that user interface for us there are a number of ways to get react working on our web page but the simplest is probably just to include these three javascript packages inside of our web page so we're first going to include react itself which is going to be the library that's going to allow us to define these components and how they behave then is react dom a special package that's going to allow us to take react components and insert them into the dom the document object model that represents the structure of the entire page and then finally babel is going to be a package that we're going to use in order to translate code from one language to another it turns out that when we're writing react code we're not actually going to be writing javascript we're going to be writing in an extension to javascript known as jsx and jsx is going to be an extension to javascript that looks a lot like javascript but has some additional features in particular it has the ability to effectively allow us to represent html inside of our javascript code in a way that's much easier to read and it's going to be convenient for us to deal with browsers on the other hand don't understand jsx automatically so what we're going to use is a tool like babel to convert that jsx code into plain javascript that our web browsers are ultimately going to be able to understand the best way to get a feel for this kind of thing is just to see it in action so i'll go ahead and create a couple of react applications just to get a sense for how it is that you can use react in your own applications as well so let's start by taking a look at react.html and what i have here is the beginning of an html page inside the head section what you'll notice is i've already included these three script tags and what these script tags are doing are just including those three javascript libraries we were talking about a moment ago i have a title for the page just called react and now let's start to fill in the body of this web page i'll begin by adding a div which i'll give an id to i'll call it app but i could call it anything and this is where our application is going to go but right now i'm just going to leave it as empty it's going to be react's job to fill in this div with the contents of our user interface and now beneath that div i'll start to write some javascript but remember i'm not going to be writing javascript per se but rather jsx that extension to javascript so in this case i'll need to add an extra attribute type equals text babel and all this is doing is telling my browser that it's going to need to translate this jsx code into javascript code that the browser is actually going to be able to understand before it tries to run this code in practice if you were developing a real application what you would want to do is you would want to do this translation ahead of time prior to deploying the application but here we're just going to translate it on the fly and so all of our react applications are going to be composed of components where a component is just some part of my web application's user interface and to describe a component i can write a javascript function so i'll create a function called app which is going to represent this app component and what's going to go inside of this app component well it's a function so it's going to return something and what it's going to return is what should appear inside of that component and this app component could really just be for example a div that says hello let's say and this is where the power of jsx really starts to come in that here i can write html like syntax inside of my javascript code and jsx is going to be able to understand it so this function right here is a function called app that is representing a react component and when this component is rendered onto my web page it's going to say hello so there's one last line i need inside of my javascript now and that is to actually render this component into the page to do that i'll say react dom dot render and the first argument to this function reactdom.render is what component would i like to render the component is this app component that i just created and so i'll say app again using this html like syntax and then the second argument is where on the page would i like to render this component and i want to render this component right here on line 10 where i have a div whose id is app so i'll need to add some javascript code to find that particular div and to do that i can just say document dot query selector and then hash app to say find the element with an id of app and that is where i would like to render this app component so i first created this empty div then i defined this function representing a react component and then after that we're going to render that component inside of the html page itself so now if we were to open a browser and see what this page actually looks like i'll make the text a little bit bigger you see that we actually do see the word hello and if i make a change to the component and refresh the page it will change the page as well so if the component instead displayed hello world well then i refresh the page and the page now also says hello world and because this is javascript i can add javascript code to the function just as i could with any function in javascript imagine for example that i had some variables like let's create a variable x which is equal to 1 and a variable y which is equal to 2. inside of this div rather than just render some text i can use curly braces to say plug in the value of some javascript expression i could plug in the value of x plus y for example and now by including x plus y in these curly braces javascript is going to evaluate what is x plus y and display that inside of the div instead and so now when i refresh the page you see that the page just says three for example and so that's the basics of react we create these components and then render those components all using the power of javascript but where react starts to get more powerful is when we can reuse components the whole idea of a component is it represents some part of the user interface and i could reuse that same component across multiple parts of the interface as well imagine for example that inside of my app component i was going to render a div that had three headings each of which said hello so there's one heading there's another one and we'll add a third one there as well so i have a div with three headings inside of it and we can see what that looks like each one of them says hello but there's some repetition here i'm having to use this h1 tag three times all to create exactly the same ui element on the page this is a case where i can create a separate component and then just reuse that component rather than have to repeat myself multiple times so how could i do that well remember that in javascript we can write a function to represent a react component so i'll add another function here and i'll call that function hello because it's going to represent this hello component and this hello function is also going to return something and what it's going to return is a heading in h1 that just says hello and so now inside of my app component rather than render three separate h1s i can simplify this a little bit to just say hello here i'm saying go ahead and render a hello component here we'll render a second one and a third one after that each time i render a hello component it's going to display as this heading that just says hello so i refresh the page and nothing changes i still see three headings each of which says hello because inside of my app component i'm rendering this hello component three times and each time it's going to display this h1 but where components start to get more powerful is when they're not always displaying the same information every time but when we can parameterize those components with properties or as react simplifies them props short for properties so what would that mean we see that html elements can take attributes likewise react components can take properties where maybe i don't just want to say hello but i want to say hello to someone hello to harry or to ron or hermione for example so i could say hello name equals harry using syntax much like an html attribute then here say hello name equals ron and then finally hello name equals hermione and so now my hello component is accepting this prop this property called name which is different for all three of these components and so inside this hello function now i would like the hello function to take advantage of these properties of these props and so i'm going to add an argument to the hello function that argument is conventionally just called props and now instead of just saying hello i'm going to say hello comma and then remember to plug in a javascript value i use curly braces and inside of those curly braces i can say props dot and then whatever the name of the property is in this case the name of the property is just name so i can say props dot name to say whatever the name prop is go ahead and plug that in right here inside of the hello component so the hello component is going to say hello comma and then someone's name so i can save that refresh the page and now i see hello harry hello ron and hello hermione three different components each of which is still just this hello component but we're rendering it with different props one time with the name of harry one time with the name of ron and one time with the name hermione and so this is where components can start to get a little bit different by passing in different props into those components we can decide how that component is ultimately going to render but let's add to this a little bit and start to add state into our react components as well and state is going to mean any kind of data that we want to store inside of the component itself and for this let's try to recreate the counter application that we created when we first introduced javascript where we were really just creating a button that allowed you to count and encounter it up from 0 1 2 3 4 etc so to do this let's create a new file i'll create a new file and just call it counter.html and we can start just by copying the contents of react.html into our counter.html file we're still going to use the same script tags and we can still have an app component but what's going to be inside this app component is going to be a little different i'll change the title of the page to to be counter instead of react so what goes inside of the app component well if we're going to do this counting we need a div that's going to display the number that we've currently counted to something like zero to start with and we're going to need a button this button is just going to be count which will be the label for that button so a div that just says zero and a button that says count and now if i open up counter.html i'll make it a little bigger you can see that i have this number zero here and a button that says count of course right now clicking on the button doesn't do anything because i haven't written any javascript code to say what should happen when this button is actually clicked on but before we get there let's modify this program a little bit right now i've written the number zero directly into the div itself but it's not always going to be zero eventually as i start counting by pressing that count button that number is going to change so what i'm going to do now is factor this zero out into what's known as state inside of my react component and here one way to create state in my react component is to use a special function inside of react called use state this is one example of a react hook that allows me to add some additional functionality into my react component and the argument to react.ustate is going to be the initial value of that state i'm going to start counting and i want to start counting from the number zero so i'm going to include the number zero as the argument to this use state function so we're going to start counting at zero and what this u state function returns is really an array of two things it's going to be a variable that i can give a name to i'll call it count and also a function that i'm going to call setcount and that function is going to allow me to set the value for the state if ever i need to change the state at some point in the future so this u-state function accepts zero the initial state as its argument and then i get two things back i get the state variable itself called count and i get a function for changing that state when i need to so now instead of rendering a zero inside of the div just by writing the number zero i'm going to instead in curly braces go ahead and render whatever the value of count is initially it's going to be zero but eventually that number might change and i want my ui to reflect the changes in the underlying state so right now if i refresh the page it still says zero because the initial state was set to 0 but i could change that if initially that initial state was some other value i could refresh the page and see a different value appear for the count instead whatever the value of this count variable is in the state that's going to be what the user is going to see when they're looking at my user interface and when they see my component so now let's make this button actually do something because right now the number is never changing to do that i can add an on click handler and notice one difference between onclick and react and onclick as we traditionally used it in javascript i'm using this capital c and that's just a common react convention when we're defining event handlers and here i'm going to say on click and then in curly braces the name of a function a function that i would like to run when this button is clicked and i can call that function whatever i'd like i'll call it update count for example and now what i need to do is define a function called update count and i'm going to define that function inside of this react component inside of my app function it turns out in javascript you can have functions that are defined inside of other functions so i'll define this function called update count and what do i want the update count function to do well what i'd like to do is just increase count by one and you might think that i could do that just by saying count equals count plus one but it turns out you can't quite do that in react in react whenever whenever i'm using this use state if i want to change the state i have to use this function that use state provides to me for whenever i want to set the new value of the state so rather than count equals count plus one i have to use this set count function and the argument to set count is going to be count plus one so set count is this function that is going to change the underlying state inside of my component and the argument is what should the new state be and in this case it's just going to be count plus one one more than whatever the count was before so i can save that and i'll go ahead and refresh the page it starts at a zero but every time i click on this count button you'll notice the count increases by one and again i have no code that's saying go into the div and change whatever is inside of the div all i have inside of this div is this reference to this state variable count and whenever the state changes javascript and in turn react knows that what react needs to do is to recreate this component re-render the component by displaying the new value of this state variable and then when the button is clicked on we're able to run this function to change the value of that underlying state so by taking advantage of these react components with state we can start to represent information inside of our components and then define what our component is going to display as a just by representing html in terms of that underlying state deciding how we should use that state in order to render an interface that the user is ultimately going to see so let's now try and put these pieces together and create a web application that uses these abilities of react to define state and to manipulate that state and in turn update a user interface based on changes that are happening to that underlying state and we'll create an application that will just display some simple mathematical questions to the user and quiz the user on some basic addition facts for example so let's create that application i'll create a new file and call it addition.html and inside of edition.html i'll start again just by copying the contents of this counter.html file because the framework the structure of this page will be similar but i'll go ahead and clear out what's inside of my app component at least for now and so what would i like for my app component to render well let's go ahead and render a div and if i want to create an application that's going to ask the user some mathematical questions and then prompt the user to type in an answer there are at least two parts of this user interface that i'm going to need i'm going to need a place to display the addition fact answer like what is one plus two for example and then i'll need an input field where the user can type in their response to that question and then see if they got the question right or wrong so inside the div i'll start by creating a div that displays the question itself something like one plus two and then beneath that i'll just add an input field eventually we'll add more to this user interface but for now all we really need is a div that displays the mathematical question and an input for the user to type in their response so now if i go ahead and go to addition.html here's what i see i'll make it a little bit bigger i see oneplus 2 and then an input field where the user could start to type in their response but just as we did before i don't want to literally write the numbers 1 and 2 into what i'm returning instead i want these 1 and 2 to be based on some underlying state inside of my application the application is going to maintain state about what two numbers to add together and then it's going to display a user interface based on that state so what could i do here well one thing i could do is again use react dot use state start this number off as one and maybe call this num1 and then a function to set number one and then i could do it again let's create num2 and set num2 to be react.ustate2 and i could have two different pieces of state num1 and num2 each of which has a different function set num1 and set num2 that are each representing the two different numbers that i would like to add together but already this is starting to get messy and over time as i add more different pieces of state to the application as we'll see in just a moment the state might start to get more and more complex with more and more different functions and variables so it's often helpful and a common practice in react to combine multiple pieces of state just into one javascript object that's maintaining all of the different pieces of state for this particular component and to do that i'll again use react.ustate but instead of setting the state initially to be a number like one or two it's instead going to be a javascript object that has keys and values where i could say let num1 be the number one and let num2 be the number two much like a dictionary in python for example where i have multiple different values num1 and num2 all together inside of the same object and i can call that state and have a variable and have a function called setstate that is going to update the value of that state and so rather than have to have all of these different variables i can simplify a little bit to just state and a function to set the state and the state now has these two different pieces number one and number two and so now instead of rendering literally the number one using curly braces i can say state dot num1 and instead of rendering literally the number two i can say state dot num2 drawing upon that state to decide what it is going to appear inside of the user interface and so right now the page appears no different but if i were to change those initial values of the state maybe make it two and four for example and then refresh the page well now it displays as two plus four and so that's helpful we now have a user interface where the numbers are based on the state but now what i'd like to do is add the ability to keep track of what the user typed in so we can tell if the user correctly typed in the answer to this mathematical problem and how would i do that well the state represents any information that we need to keep track of inside of this component and so in addition to storing the two numbers inside of the state i likely also need to keep track of a third piece of information which is the response what did the user type in into this text field and so i'll add a third part of the state called response that initially will just be the empty string will just be nothing and then this input field i'm going to give it a value and the value is going to be state dot response whatever the user typed in as the response that's stored inside of the state and that is going to be the value of what shows up in the input field and so that way whatever's in the input field will have access to it inside of this state.response variable but there is a problem and here's the problem i'll try refreshing the page i'll go into this text field and let's say i know the answer i know 2 plus 4 is equal to 6. i'm now going to press 6 on my keyboard but as i press 6 on the keyboard nothing's happening no 6 is appearing inside of the text field even though i am pressing the key on the keyboard so why is that why is the text field not updating well the reason is the value of the input field whatever appears in the input field is this value state.response and state.response is always this empty string and never changing what state.response is equal to and so i need to change this a little bit i need to add as an attribute to this input field on change meaning when the input field changes i need to do something and i'll call a function that i can call update response but again i could call that update function whatever i'd like it's just the name for the function that's going to run whenever something changes in the input field so let me now define that update response function i'll define a function called update response and because it's an event handler it can accept an argument which is the event itself the fact that something has changed inside of the input field and when i have access to this event it turns out that if i want to figure out what it is the user has typed into the input field i can get at that with event.target.value and i'd only know that by looking at it in the documentation but what i'd like is for event.target.value to be the new value for this response and so what i'd like to do is do something like this set state and what should the new value of the state be well i would like for response to no longer be the empty string but to now be event event.target.value and that is going to be the new value for response but i'm not quite done yet because state doesn't just have response as one of the parts of the state the state also has num1 and num2 and those two pieces aren't really changing so i could say all right num1 is just going to be whatever state.num1 was that's not changing and num2 is going to be whatever state.num2 was that's not changing the only thing that's changing is the response but this is starting to get a little bit verbose and especially if i start adding more and more different pieces to the state it's going to become difficult to manage if i constantly have to repeat myself for all of the parts of the state that aren't changing ideally what i'd like to do is just specify the parts of the state that will change and ignore everything else and so one shorthand way to do that in javascript is to use what's known as the spread operator and it looks like this dot dot dot and then state and what this is saying is just use the existing values of the state for everything else like num1 and num2 the only thing to override is the new value for the response and so this syntax here is my way of saying i would like to update the state everything should stay the same except for response which is now going to be event.target.value in other words whatever it is the user typed in into that input field and so i'll go ahead and refresh the page and now if i type a number like six you actually see that number appear in the input field so that's great we've now displayed a question where the numbers are stored in the state and the user can type in a response where that response is also stored in the state now what i'd like is when the user presses the enter key on their keyboard we check did they get the answer right or did they get the answer wrong and so how would i do that well the first thing i need to do is in this input field somehow detect when a key is pressed when a key is pressed what i'd like to do is check to see if it was the enter key and if it was the enter key then let's go ahead and check to see what the actual sum of the two numbers is and see if the user got that right or wrong so let's add an event handler on key press is going to be equal to something again i can name this function whatever i'd like i'll call it input key press but again i could name that anything and now let's define that input keypress function so up above i'm going to define this function called input keypress again it takes that event as its argument and this event is going to happen any time a key is pressed regardless of whether it's a letter or a number or the enter key and so i want to check to make sure that the key is actually the enter key that's the only time that i want to now check to see if they got the question right or wrong so i'll add here a condition it's just javascript so i can say if event dot key is equal to enter well then let's go ahead and check and otherwise we don't have to do anything i don't need an else case here because nothing should happen unless it's the enter key that was actually pressed and so now how do i check to see if the user got the answer right or wrong well inside of state.num1 is the first number and inside of state.num2 is the second number so i could have a condition that checked if state.num1 plus state.num2 is equal to state.response which is what the user typed in into the input field but that doesn't quite work because state.response that's a string the user doesn't necessarily have to type in numbers it's possible the user is going to type in some letters instead for example or other characters instead and so what i'm going to do first is convert the response into an integer if we're able to do so so i'm going to define a variable called answer using the javascript function parseint that takes a string and tries to convert it into an integer so we're going to parse the end state dot response and now we can check if number one plus number two is equal to the answer well then this means the user got the question right and else if the sum is not equal to the answer that means the user got the question wrong and so now what i could do is handle those two different scenarios in one case the user got the question right and we should do something and in another case the user got the question wrong and we should do something else and we're making that decision by looking at the state of the application by looking at what two numbers we're supposed to be adding and looking at what the user typed in as their response so what should we do when the user gets a question right or gets a question wrong well maybe this game is going to keep score by maintaining a number for how many questions the user has gotten right and every time the user gets a question right we could increase that score by one and any time the user gets a question wrong we could decrease that score by one for example so how would we do that well the score is some piece of state inside of the application and so we're going to need to add to the state right now in the state we're storing a number one a number two and a response i'll add to that a score where the score is going to start out as just zero and we can render that score on the page if i scroll down to where we're returning the div to render let's add another day of it that says the score is and then using curly braces plug in whatever the value of state dot score is whatever the score is let's figure that out from the state and let's display that in the user interface so now this user interface shows not only a question and an input field but also a score and the score starts out as just the number zero so let's now go back to this function when a key is pressed if it's the enter key let's check to see if they got the answer right or wrong we check did the user actually get the question right if so what should we do well we should increase the score and how do we do that we do that by calling the set state function all of the state is going to be the same so using that dot dot state spread operator the only thing that's different is the score is going to be state dot score plus one so we're updating the state to increase the score by one and if the user gets the question wrong let's set the state to be dot dot state and then the score is going to be state dot score minus one so if the user gets the question right we increase the score by one otherwise we decrease the score by one and let's test that to see what it actually looks like when we try this in the user interface i'll refresh the page two plus four if i type in the correct answer six press return the score increases by one if i typed in the wrong answer and say eight press return the score decreases by one so this appears to work depending on whether i get the question right or wrong the score is able to update increasing or decreasing based on the result of that condition now this game is pretty easy to get a high score on right now because i can just keep pressing return over and over and over and the question's never changing my response is already there and so the score keeps going up and up and up so let's make the game a little bit more interesting every time the user gets a question right let's display a new question for them to answer and how would we do that well the question that's displayed to the user is based on two underlying pieces of the state of the component it's based on state.num1 and it's based on state.num2 so if i want to change the question all i have to do is when the user gets the question right and i'm updating the state instead of only updating the score let's also update num1 and num2 and i could set these to be specific values maybe like 5 and 10 for example but let's make it more interesting and display a random number every time we'll generate a random number and so the user will be adding two random numbers together every time they get a new question right how do we generate a random number well math.random is a javascript function that generates a random number between 0 and 1. we can multiply it by 10 so now we're getting a number between 0 and 10 but we don't want any decimals to appear in the number so i'll go ahead and take the ceiling of the number math.seal to say if the number was like 5.8 we'll just go ahead and round that up to six for example and we'll do the same thing for number two we'll take the ceiling of math.random times 10. so every time the user gets a question right we'll update num1 and num2 to be new random numbers generated just like this and so let's go back and try it again we see two plus four i type in the correct answer six and the question changes eight plus five i type in the correct answer press return my score increases and the question changes again this time if i get the answer wrong i type in 10 for example watch my score decrease it went from two down to one but the question didn't change now i get another opportunity to try to answer this question and when i answer it correctly the score increases again from one to two so this game is starting to come along now it's keeping track of my score it's displaying different questions there is at least one user interface quirk right now and that is the fact that at the moment when i get a question right and press return i type in six and press return the six still stays there ideally i get a new question i'd like to clear out the response so the user can just type in whatever the new answer is rather than have to delete whatever they typed in before and then type in a new number so how could we do that reset whatever is inside of the input field well what's typed into the input field is stored inside of the state of my component it's stored inside of state dot response and so if i wanted to change that all i would have to do is say let's change the response to be the empty string when the user gets a question right we're going to update these two numbers increase the score and also clear out the response so that it's just the empty string and i can do the same thing if the user gets a question wrong decrease the score by one but also clear out that response back to the empty string so that there's nothing there and so now we get a question i type in an answer press return and the input field clears out i get a new question and the score increases by one four separate pieces of state all changing at the same time and that gets reflected in the user interface that i'm now able to see so i type in another value and the score increases and everything updates again all right so that's definitely progress one other user interface quirk that i noticed here is that the input field by default isn't automatically selected where i would have to go in and click on the input field in order to highlight it so that i can start typing in my response i can fix that pretty easily if i scroll down to where the input field is we'll add an auto focus attribute and just set that to be true so that the input field automatically focuses when i load the page for the first time so now i refresh the page the input field is already highlighted and immediately i can start to try to play this game so now that we have the basic functionality of this app working let's try and improve the css so that the game looks a little bit nicer i'll scroll up to the top of the page and add a style tag to the head section of my html page and i'd like for this entire app to be centered so i'll say text align is going to be center and i'm going to set the font family to be sans-serif because i prefer that font for this particular game so i refresh the page and now everything is centered and the font is different than what the default was and what else would i like to have changed well this problem two plus four maybe i'd like for that to be bigger i'd like the problem to be big and the score beneath that that can stay the same size that it is right now so how would i do that well if i go back to the html here i'll go ahead and give this div where i'm displaying the problem number one plus number two i'll give it an id of problem and then if i scroll back up i'll say for the element with an id of problem let's go ahead and set the font size to be 72 pixels for example just to make it bigger and so now i see a big math equation 2 plus 4 for example the input field and then the smaller score beneath it so that's a nice ui enhancement a little bit and now i can play the game get a question right and the score increases i get a question wrong and i get to try again but maybe i'd like to offer more of a visual indication that the user got a question wrong maybe anytime the user gets a question wrong i'd like to change the color of this text instead of being black instead it should be red when the user gets a question wrong and how could i go about doing that well we can change the color of something just by using css if we had like a class called incorrect for example if i scroll down here and give this div a class name which is how you add a class in react of incorrect then i could use this class name to style it as red or not red so i could say anything that has a class of incorrect let's go ahead and give that a color of red and so now because i gave this problem a class of incorrect and i said turn all incorrect text to be read we now see this text appear as read but this again is not quite what i want i don't want it to be read all of the time i only want it to be read when the user has just gotten a question wrong when they were just incorrect in answering a mathematical question and so how could i represent that information inside of my application well i'm going to need some additional state state again is any information that i need to keep track of inside of my component and now it seems that in addition to the response and the score and the numbers i also want to keep track of did the user just answer a question incorrectly or not so i'll add another piece to the state i'll call it incorrect and initially it will be false they didn't just get something incorrect and now here if i scroll down to this class name rather than have it be incorrect all the time let me add in curly braces an expression i'll say if state dot incorrect is true using the ternary operator with a question mark then the class should be incorrect but otherwise it shouldn't have a class of incorrect it'll just be the empty string and so this expression here allows me to change the class of an html element based on the underlying state if state.incorrect is true then this div will have a class of incorrect and otherwise it won't and so now when i load the page for the first time the text appears as black and what i need to do is when the user gets a question wrong i need to change the state to indicate that they just got a question wrong how do i do that well here is the set state call when the user gets a question wrong and in that case i'll go ahead and set incorrect equal to true and when the user gets a question right we'll go ahead and set incorrect equal to false we're modifying this one additional piece of state based on whether the user got the question right or wrong so now if i load the page answer a question correctly the score increases and i get a new question but if i answer a question incorrectly and press return you'll notice the score decreases the input field clears out and the text changes color because i changed the value of that incorrect part of the underlying state and based on that we were able to see the text color change as well if i now get a question correct press return the text color changes back to black and the score increases and let's now add one final piece of state or one final change to the ui for this application let's give me a way to win this game maybe once i get to a score of 10 by answering 10 questions correctly then we're going to win the game and how could i do that well remember that each react component can just be a javascript function and this function is just immediately returning this div but it's a function so i can add additional logic to it i can say if state dot score is equal to 10 for example then rather than render the old div let's run return a new div this div is just going to display something like u1 and so that i can style it i'll give it an id the id will be winner and if the id is winner let's go ahead and make the font size 72 pixels and let's make the color green if i win so i added some css just to style it but really the only new logic is further down below where i'm here saying check the state if the score is 10 well that means we win so instead of returning the new problem just return a div that says you won the game so let's try that now i get these questions every time i answer a question you're noticing that the score is going to increase by one and every time we're generating new random numbers to display as the as what's going to appear in the user interface and once i get to question number 10 if i answer it correctly press return the entire ui changes instead of the problem and an input field and the score i just see in green large text that i won and again i was able to do that by looking here at this condition where we're looking at the value of the state and if the state is 10 we're deciding what's a retina and this again is one of the great powers of react this ability to use this underlying state and based on the value of the underlying state decide what it is the user should see in their user interface and react is just one of many libraries that do this type of thing other popular ones include angular and vue where all of these are just these web frameworks that make it easy to be able to create applications that are able to respond to some underlying state so that you the programmer don't have to worry about constantly having to manipulate various different parts of the page which especially especially as you imagine websites like facebook or twitter where there are many things happening on the page at the same time every time a new tweet comes in you might get a notification and see a new post in your main area of your news feed so these are the types of things that you might want the application to be able to more easily handle for you where you describe what the state is you describe what the page should look like based on that underlying state and let the library whether it's react or something else begin to handle the process of doing that for you and the world of user interfaces is changing pretty quickly that a lot changes in user interfaces in terms of the technologies and the tools that are quite popular but they're really based on the same set of underlying ideas the idea that we can use javascript in order to manipulate what it is the user sees on their page in order to detect what's happening based on particular events like scrolling to the bottom of the page or typing something into an input field and then responding to those particular events by providing some sort of function that gets called anytime a particular event happens by mixing that in with other features like the ability to asynchronously request information from an external server or the ability to do computations based on the values of the state like we saw within react we have the ability to create very interesting engaging dynamic user interfaces very very quickly all just using the power of combining python and javascript that was web programming with python and javascript for today we'll see you next time
Info
Channel: CS50
Views: 50,258
Rating: 4.9674468 out of 5
Keywords: cs50, harvard, computer, science, david, j., malan
Id: jrBhi8wbzPw
Channel Id: undefined
Length: 100min 15sec (6015 seconds)
Published: Wed Jul 07 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.