Build a Single Page Application with JavaScript (No Frameworks)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys how you going my name is domin in today's video we're going to be creating a single page application using vanilla javascript okay so no frameworks are required in order to achieve this we're going to be doing all of the client-side routing ourselves okay so just for those of you who aren't too sure our single page applications are basically just web pages or applications on the web which have a single html file and then all of the content and components and the views and things like that they're all loaded dynamically using javascript through ajax or fetch requests to the server side to retrieve data and things like that so essentially it's supposed to operate like a native application so that includes quite importantly no page refreshes and things of that nature okay now i want to tell you also that today's video is going to be split into two separate parts we're going to be getting back to that very shortly but let's just go ahead now and take a look at the at the finished product okay so right here is the application itself so as we can see very basic application now if i was to navigate to the post section we can see right there that this this right side here is the is the view that changes okay so we have the dashboard view we have the posts view and we can see here of course we have client-side routing for forward slash posts then of course the roots and then settings now we can even go inside here and click on a post and we can see we actually get client-side url parameters so right up here we get post forward slash 2 for the id of the post and of course that is then accessible inside the javascript right here so this part right here this uh this client-side url parameters this right here is going to be for the next video the reason why i've decided to split them up is because this right here adds a bit of complexity to the project so i didn't want to over complicate things for people who just want the basic functionality right here but of course most of the content is going to be covered in today's video anyway so let's go inside the text editor right here and we're going to start by firstly creating a new directory for the front end so we can say front end right here and inside here we're going to have of course the html the css and the javascript okay so let's go inside here now and we're going to be uh making a new index.html file so very shortly we're going to be writing the the actual web server using express and every single every single route is going to go back to the single index html file which of course helps the single page application nature of this project okay so inside here we can include a html template okay and we can simply just say for the title single page app okay now we can also include some javascript so let's go down here we're going to say script with a source this is going to have a type of module because we're going to be taking advantage of es6 import export syntax primarily due to the fact that each one of our separate views here so dashboard posts and settings they're all going to have their own javascript class so that's why we're going to be using the es6 input export syntax with modules okay so for the for the source this will be going to forward slash static and then we can just say a js right here and we can call this one index.js so this one right here is our front end or our client-side javascript entry point okay so now we can write some basic navigation so let's go up here and i'm just going to copy and paste some really simple html so i'll copy this from here and paste it inside here so as we can see here fairly straightforward html just a nav with a class of nav and a few links inside here now as we can see i've got individual classes on the actual links themselves but more importantly i've got the hrefs right here for each one of our separate routes so we can see here of course forward slash posts forward slash settings now what's also important is that we've got a data dash link data attribute right here so i forgot to mention earlier but this will be done using the history api so essentially any one of these anchor tags with an attribute of data link should use the history api the push states method to navigate to that particular resource to avoid a page refresh but we're going to be coming back to this very shortly when we get to the javascript itself but for now let's just keep that the way it is for the css and to make the web page look nice because that's not too important we're going to be leaving that to the very end okay so let's just have this html right here just for now and we can now work on the actual web server itself okay so let's go inside here and we can open the command line for this for this directory and we can now create a new node.js project for npm init dash y and once that's done we can now include express so let's do npmi and install express just like that okay so now we can create the server.js file so we can make a new file right here for server.js and inside here we can of course include a few dependencies so that is going to be if i can just get it up here that is going to be express okay equal to require and we can bring in express and the same goes for path okay we can now create the express app so const app equals express just like this and now we can just do down here app dot gets okay forward slash all and now inside here we can simply grab the request and the response and we can simply just say rest dot send file then pass through here path dot resolve then pass through front end and then index.html so all of this stuff right here basically what we're doing is we are saying any route so any any path at all we're going to go back to the root uh you know this this handler right here and we're going to simply send back our index html so that means no matter what path i send to the web server if we go to posts or settings or whatever it is they're all going to go back to this index.html and this right here is quite quite important to making this a single page application so we're going to see how this works very shortly but for now let's now do app.listen let's start the server on process.emb.ports or let's just default to 5060 okay now we can simply just say right here for the listening listener we can just say console.log and we can say a server running just like this okay cool so now let's just save this and then start the server we can say no server.js now go into the browser and go to localhost that port 5060 and we can see here we get this right here now of course this is going to be the index.html file but what if i was to go to something like forward slash settings okay that takes me back to the same index.html and of course that right there is crucial to our single page application because if i was to send you know this link right here for this post okay to my friend and he opens it up you know in his own browser if he goes to this link he wants it to go back to the index.html and then it's going to be handled on the front end to decide what gets displayed and of course that right there is you know it contributes to the single page application nature of the web page okay so let's go back inside here now and we're going to deal with this problem right here so we can see when we try to include the js file right here of course this file currently does not exist but the problem is if we go back inside here we can see of course we get fail to load module etc etc if we go to the actual resource itself right here in a new tab we can see we actually get the same index.html and that right there is of course due to the fact that every route or every path goes to this one right here okay so in order to fix that we're going to firstly define the static directory inside the front end the front end directory so we can say static right here and we can make a new directory inside here called js and inside here now we can simply make a new file called index.js and this one of course is going to be our index.js our front end or client-side entry point so now we can simply just say console.log we can say js is loaded just to actually test and see that it works okay now let's save this and refresh and we still have the exact same problem as we can see right here in the console so to fix that now we can go back inside the express code and we can simply use some middleware to serve the static directory so we can say right here um app.use then say forward slash static okay then we can say express dot static okay then pass through here path dot resolve then do name and then we can say front end and then static and to be honest i can probably just make it without this right here as i did earlier you know what actually it's probably best to include that for both so let's go inside here and just include a dame for both of these okay just like that now of course now this this is basically saying whenever the path has forward static inside of it so for example this one right here for the js so whenever it has forward slash static we're going to simply serve the static directory as per usual okay so of course front end then static so now if we were to restart the server okay we can now of course minimize the the terminal just for now okay now restarting it we can now refresh this page and we can see the js is actually working this time so if i was to refresh this now let's just go back to the root right here we can see we get right here js is loaded okay so all of that is now set up we can move on to writing the client-side javascript itself okay so let's go back inside here now and we can move on to this index.js so the first thing i want to do is i want to write the actual client-side router okay so right here we're going to say const router is equal to a new asynchronous function okay now the reason why it's going to be asynchronous is because we're going to be loading the contents for each one of our views so dashboard posts or settings we're going to be loading that inside here now some of those views so for example let's just say it's settings right for settings maybe the actual client side wants to make an asynchronous request to the server side to get some settings before it actually renders or shows the page so in order to achieve that we can use an async function so right here and that's just going to make our code a lot simpler to work with okay so we're going to be getting back to this and why it's important a bit later on but for now let's keep that right there now so inside the router we're going to be defining each one of our roots okay so we can say const roots right here equal to a new array of roots okay so inside here now we can just define a new object okay and we can say right here a path for forward slash okay so that is the root path of the web page okay now a second property here is going to be view so for the view we're gonna just for now we're gonna have this be a function so we're going to say right here console.log viewing dashboard just like that okay so right here we're basically saying whenever the user goes to the root the actual root path okay we're going to run this function right here that is what we want to do in order to make this work we can do the same thing for two more it's going to be posts and settings so we can say right here posts and then we can say viewing posts and then for settings the exact same thing okay just like this um so now uh we can essentially just loop through each one of our routes or our routes and we can we can see if any of these match okay so down here we can just say test each route for potential match okay so we can say const potential matches is equal to roots.map so we can say roots.map right here now we're going to be looping through each map like i said earlier and we're going to be returning a new object for each route okay and that is why we're using the map method so inside here we're going to grab each route and we're going to simply return a new object so we're going to say return we're going to return this object right here which will contain the root itself okay so root equal to root and then we can say right here is match so is match is going to be a boolean value we're going to say location dot path name is equal to and then root dot path because if i was to go in the browser right here and i say location dot path name we get this forward slash right here if i go to forward slash posts for example and then do it again we get forward slash posts okay so we're testing to see if this pathway here matches against any of our routes or our route paths right here okay cool so now we can simply just console.log and we can log out the potential matches right here so let's save this and then refresh the page now unfortunately we haven't actually called the route i'm sorry we haven't actually called the router just yet so let's go back inside here and we're going to go down here and we're going to say document.addeventlistener we're going to listen for the dom contents loaded event so once all of the dom has loaded up we can simply just run this function okay just like that so now let's save this and refresh and now we should see we get right here of course each one of our potential matches so we can see at forward slash posts we get right here is match true okay so of course we have now the view itself so a path then the view itself equal to of course our function so it's going to be quite straightforward now of course these ones are is match false so we can simply ignore those so now we can simply go back inside here and we're going to look for our match so we can say right here let's match is equal to then we can use potential matches dot fine so the find method is going to look through the array and find something which matches a particular condition which we're going to define right now so we're going to grab the potential match okay so we can say potential match right here as singular and we can say right here potential match dot results you know what my mistake this needs to be potential match is match okay so basically now this let match is going to be one of these so in our case for this example it's going to be four slash posts so it's going to be the post's roots is match is going to be true so of course this this function is going to return true so it's going to find it and give us the match right there so if i was to console.log and pass through match we can save this and refresh and now we get right here the actual root and then of course is match equal to true okay so what happens if i go to forward slash and i say posts then do something like i don't know posts by me something random like that okay we do this and we get undefined for the match of course because this right here doesn't actually match anything so how do you solve that you need to define a basically like a four or four a not found root okay so let's go back inside here and we're going to say right here if if no match so if no match we can simply say match is equal to then we can just pass through here let's pass through roots is equal to roots at index zero okay and now just to keep consistent uh to keep consistent we're going to pass through is match equal to true as well okay so right here we're just saying if we have no match we're going to default to roots index 0 and the index 0 root is going to be the dashboard one right up here so of course you might want to define your own custom for or not found root if you like and then use that for inside here but in my case i just want to have the dashboard as the default okay so now let's try again console.log match and this time we can see we get the default route right here now you might be wondering why have i set is match true why is this important it's going to make a lot more sense in the second part of today's video when we get to client-side url parameters but if you're not doing that you could potentially skip the step this step of actually including the is match property but like i said we'll get to why that's there in the next video okay but anyway let's go back inside here now and we're going to finish off this router so we can simply now say console.log match dot roots okay sorry my mistake match.root then dots sorry view okay so as we can see the view property is going to be an actual function in our case so we can simply then call the function just like that we're going to be changing this very shortly to actually be an actual class okay but let's just save this for now and refresh and we can see now we get viewing dashboard for posts by me what if i actually go to the dashboard itself we get of course the same thing viewing dashboard what if i go to forward slash posts we get viewing posts okay so that's all working perfectly fine so now before we get to actually rendering the correct content for the posts and the settings and things like that we need to create a few helper functions and do a few more things okay so what if i want to navigate using the history api so basically as we can see right here when i go to posts it redirects to posts without actually loading a new resource okay so in uh in order to achieve this we're going to be making use of the history api so let's go back inside here and we can define a new function right up here it's going to be called const navigate to okay and this right here is going to take to a url okay this url is going to just simply say history dot push states okay so we're going to push this state for null then null then url then we can simply call the client side router to then you know process the new history entry okay and now we might just uh we might just add some some some event listeners for the actual links themselves so basically whenever the link has data link we need to run this this navigate to instead of the default behavior of refreshing the page so if i just go back inside here now we can see if i was to click on these links they actually reload the page right up here so we need to basically make it so when i click on these links we're going to instead run this function right here okay so let's do that right now it's going to be quite straightforward inside the dom content loaded we're going to say right here document.body.ad event listener we're going to listen for the click event so this one right here is going to be a delegated event listener okay the reason why it's going to be delegated is because if you add new content to the page which has those links you want the actual links to work okay so we can say right here e so grab the event object and we can simply say if e dot target dot matches so if the target matches the query of data dash link or sorry the selector of data dash link okay we can simply just say uh e dot prevent default then we can say navigate to then pass through e dot target dot h ref okay so right here um the e dot target if i click on one of these links right so if i click on this one right here the e dot target is going to refer to the actual link element itself okay so then we're saying okay does this link element have the data link attribute if it does then we're going to say dot prevent default so prevent default is going to prevent the default behavior of actually following that link and we're going to instead say navigate to and then navigate to the actual href as sets on the element itself right here okay so now let's save this and then refresh and we can see if i go to the root right here if i click on posts we can see we go to posts without a page refreshed and also we get viewing posts right here the router has done its job okay let's go to settings and it works in the exact same way we get no page refresh what if i was to remove this data dash link attribute from a post for example refreshing going to post will now actually redirect to posts okay it still works but of course it is not as fluid without a page refresh so let's go back inside here now and we can just put that back and we can move on now to one last thing and that is going to be whenever the pop state changes so essentially if i was to go back inside here we can see if i refresh now if i go to settings okay we get viewing settings now what if i was to go back to posts we don't get viewing posts so we can see when i navigate through the history it doesn't actually re-run the router so we need to make it so upon the user navigating through history we need to actually run that router so let's go back inside here we're going to simply say it's a one-liner we're going to say window.addeventlistener we're going to listen for the pop state event and right here we're just going to say router just like that so now let's save this and refresh and now if i was to navigate through the actual history right here so let's go back now we can see we get viewing posts and it's all working perfectly fine via normal navigation just like this okay cool so now it's gonna just be about changing these boring console logs to be actual classes which contain content okay so let's go back inside here and we can go inside of course this static directory and we can make a just a new directory inside the js called views okay so i might have called these things sorry these things pages a couple of times in today's video but basically i'm going to be calling them views from now on so a view is basically just dashboard this part right here this part and then this part the reason why i didn't want to call them pages is because of course it's supposed to be a single page application it technically is and these are just sort of like sub pages or different views okay so these right here are going to be the views so you basically need to have a single javascript file for each one of your views okay so let's go inside here under views we're going to be creating firstly just an abstract view so all of the view classes are going to inherit this one right here so i'm going to say abstract view just like this dot js now for this one we can simply just say export default class okay just like this and we're going to be defining the constructor right here now the constructor isn't going to do anything for this video but in the next video it's going to be handling the parameters but like i said in today's video it's not going to do anything but you might want to keep it there as a placeholder just for now but we're going to have two methods we're going to have set title this will take in a title and this right here is just going to be for the page title so we can say document.title is equal to title right here so now when you go into the dashboard class which we're going to be defining very shortly you can simply call set title and pass through dashboard and of course it's going to update the page title as we can see right here in my example if i unpin this we can see the dashboard is right up there if i go to posts it updates the title right here and then so on okay so that is what that set title is for now right here we're going to also say async get html so um in this case right here for the abstract view we can simply return nothing so whenever we have a view for example dashboard which is going to extend this abstract view of course it is going to override this get html and it's going to of course provide its own html for that view okay so now if all that if all that sounded confusing it really isn't we can now just go ahead and finish the job and it's going to make a lot more sense okay so let's go inside the views directory right here make a new file for dashboard.js so inside the dashboard we're gonna extend from this abstract view okay so we can simply say import abstract view from then dot forward slash abstractview.js just like that now we can say export default plus uh extends abstract view okay inside here now we're gonna we're gonna define the constructor like i said just for now um you know what actually let's let's remove this you know what no no my mistake we need this we need to call this dot set title we need to say set title and then pass through dashboard so of course this set title is going to come from the abstract view right here and of course set the title to be dashboard okay we can now say async html or async get html then return here a template string using the back ticks right here we're going to return a huge chunk of html so i'll just copy and paste my previous example it's going to be something like this so this right here is the html for the dashboard view now the reason why it is asynchronous is because like i said earlier maybe you want to load this html right here from the server side maybe your server side renders your html so of course you can use the fetch api or ajax whatever you want to simply then grab the data and then return it from this method so that is why we're using async right here okay cool so now we have essentially this dashboard view and of course the abstract view we can now make use of it and essentially just inject this html inside our router right here so let's make a few changes to the router we're going to firstly just comment out these two and just keep the dashboard just so we you know keep it simple for now and we're going to firstly or secondly import the dashboard from up here so i'm going to say import dashboard from dot forward slash views okay then dashboard.js just like that so now right here we can replace the function with the actual dashboard itself okay so that right there is the dashboard class reference so now we can go down here back to this section and we can simply just say if i can find this we can simply just say uh const view is equal to new match dot roots dot view just like that okay so now we're basically just creating a new instance of the view at the match roots right here so of course the roots refers to one of these right here we're saying root dot view grabbing the dashboard and of course making the instance right there now the final step is going to be down here document.queryselector we're going to select the app the app element which we're going to create very shortly but we can select the app element and we're going to say dot inner html is equal to await view dot get html just like that okay so essentially right here we're simply getting the html from this method and injecting it inside the inner html of this app element right here which we can now create so let's go inside the html and make a new div right here with an id of app right there so now saving this and refreshing we get something like this it didn't work let's try and find out why let's go inside the network so static js views dashboard.js um that should be working i think so we get static js ah okay this needs to be in the views directory right here so js views makes sense let's try again refresh and we get the same problem do we okay ah right okay my mistake let's go back inside here and we need to call the super constructor from inside the dashboard so we can say super right here and now we are good to go let's save this and then refresh and hopefully now we get our results we can see right here we get of course the content for the dashboard now of course i just copy and pasted some html but you may notice that of course we have right here view recent posts so what's that about well let's go inside here this has an anchor href posts with a data link attribute so this right here is what i was referring to before when i said we're creating a delegated event listener because we need to basically make it so if i inject new html we want this link to still work so if i go back inside here now i can actually click on this link and we can see we go to forward slash posts using of course the actual router and the push state method okay so now i might just stop here and inject or not inject but implement the css okay so let's go back inside here real quick and we can make a new directory inside static for css okay now inside here we can just make a new a new file this will be index dot css now inside here i'm just going to copy and paste my css from the example okay because all of this css is quite self-explanatory it's very straightforward so we're simply adding a font family we're adding navigation menu to make it you know dark background on the left side there we have the link itself we have the nav link hover and the app itself and of course some styles for the anchor so i'll be leaving this right here and the rest of the code inside the description below if you want to download it or check it out but that right there is going to be the css so let's go inside the html and of course include that css so go up here we can say link for css it's going to be static then css then index.css so now saving this and refreshing we get this right here okay so let's do the uh the final two views right here so for posts and dashboard sorry posts and settings so let's go inside here and we're going to be creating uh my mouse just died sorry guys i'll be a sick okay we are back so um yeah we need to we uh we need to create uh sorry guys um we need to create a new view right here for the posts.js and this will simply extend of course like we did earlier the abstract view so i'll just copy and paste the dashboard code and put it inside here let's make this posts okay and then for here we can simply just let's copy and paste my my html from the previous example you know what actually let's not do that let's have right here posts and we can just write something else we can just say you are viewing the posts something like that okay let's save this go inside the index.js we're going to import the posts view just like this and of course we can now replace this right here with the actual post the posts view just like that let's do the exact same thing for the settings.js just to finish the job so copy all of this go inside here we can say set title for settings then i can say settings right here and i can say manage your privacy and configuration so all of the settings stuff right there now back inside here the exact same thing import the settings and place it right down here okay let's save this and refresh and now we can see upon going to settings it doesn't work of course not let's figure out why uh okay let's try it again save this refresh go to settings and it's working perfectly fine if i was to click on or if i was to copy and paste settings go into a new tab and go to that we can see it still goes to settings so i can share this link right here with a friend and it's going to work perfectly fine okay so i think that right there is going to wrap up the first part of this whole uh you know this tutorial i guess of course in the next part we're going to be taking a look at our side url parameters so of course having the forward slash two and having access to these guys right here so that will be for the next video but there you go guys that is how to create a single page application using vanilla javascript thanks for watching guys and i'll see you later
Info
Channel: dcode
Views: 237,195
Rating: 4.9277449 out of 5
Keywords: code, coding, programming, tutorial, introduction, beginner, walkthrough, guide, software, development, simple, easy, english, with, example, examples, developer, lecture, recording, how, to, js, javascript, web app, web application, single page app, spa, client side routing, routing, router, react router, vue router, front end, client side, history api, push state, pushState, API
Id: 6BozpmSjk-Y
Channel Id: undefined
Length: 37min 40sec (2260 seconds)
Published: Mon Aug 24 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.