Inside Look: Coder’s Tape
Lesson 2 of 2 · Inside Look: Coder’s Tape – e02 – Autocompleting Lessons with vue-youtube-embed & portal-vue · Education
Inside Look: Coder’s Tape – e02 – Autocompleting Lessons with vue-youtube-embed & portal-vue
welcome to another episode of the inside look of creating the coders tape website if you're not familiar with the series in this series we actually are just
taking a look at how I am creating the coders tape website and I'm bringing you along so you know the tips and tricks powering this actual production app so today we're gonna be working on a
feature that I think it's kind of cool there's gonna be a lot of you involved so I think that you'll really enjoy this so right now if you took a look at any of these episodes if you are logged in
you can actually mark any of these as completed let me head back over here and you see that this one is now marked as completed if we go to the second episode what we have here is a mark as complete
so yes I could hit the button whenever I'm done with this episode but what I want to work on today is detecting when this video that is playing up here ends and when it does I want to simply mark
it as complete automatically now this is kind of an expected behavior whenever you've finished a video it means that you basically completed the lesson so instead of having to manually do it
I want to automatically do it now this is a little bit tricky and the only reason why is because this is actually a YouTube embedded player it is not an actual player in my website so let's
jump to code and let me show you what I have for that if we go to my lessons show view and we scroll up then of course we see the notes and we see this right here this iframe so this iframe
here is what YouTube actually gives us whenever you want to embed a YouTube video now all it is is just going into the embed and using what I call the lesson path which is just simply the
code that YouTube gives it we're able to create a player right on the website let me actually jump over to the local version here's my local version of it and so what I want to do is if we go
into any one of these lessons then of course we do have a video let me go ahead and log in and now that we are logged in then of course we do see we can mark as complete so we're gonna have
to do a little bit of change but in order for us to actually be able to use this in view there's a very nice view package that we can use so let's take a look at that now let's do a quick
google search for view youtube embed and if we look right here is called view YouTube and beddit now this package fairly simple to pull in we really just need to use it but then the nice thing
is this if we scroll down a little bit we have these events and these are the events that I want to hook into of course the one that we are interested in today is this ended event so this is
gonna allow us to hook up to an event that occurs in the player of course in our case when the video ends I want to go ahead and hit a specific endpoint and I want to complete the lesson that way
when the video is done the lesson is already marked as complete so let's go ahead and pull this in and follow the instructions and see what we have to do so of course we're gonna use NPM for
this so all we need to do is copy this let's go back to the terminal and I do have NPM run watch already running in the background let me create a new tab and let's go into my code escape
directory and then let's go ahead and run that NPM command to pull in the view YouTube embedded package while this is running if we go back here let's take a look at the instructions so it looks
like all we need to do is import YouTube and then we can use this view dot use this is the way that we tell view that we're gonna have this external library that we want to pull in so let's go back
to phpstorm so now let's take a look at our app that jas file let me pull it up here on the side if we take a look at resources jeaious here it is app dot j s so this
is the father we are looking for remember this is the father bootstraps all of the front end in laravel I do have a couple of components already in place but right underneath the
components we can hit paste so now we have access to this view YouTube embedded plug-in and we're telling view to go ahead and use it let's see what's next in the instructions let's go back
to Chrome and here it is so the usage for this is we simply have to call this YouTube and then it needs a video ID and then the video ID now if you recall the video ID in my case is that path
it's this one right here this lesson path so let's go ahead and give this a shot let me copy this and bring it in here just for now I'm gonna of course comment out the iframe because I don't
need two players our video ID we're going to grab using this blade syntax right here that we had before now in the documentation this is being bound but if we were to actually bind this into place
it wouldn't actually work because this right here just needs to be treated as a string so we're gonna go ahead and not bind the video ID so if we go back to Chrome if we did everything correctly
when we hit refresh of course we should get the exact same thing so we did perfect so that's good news now the thing about this is that for us to be able to actually listen to this event
let's go ahead and wrap this in a component so once we wrap this in a component we're gonna be able to actually have control so let me go ahead and cut this out and let's create a new
component let's go into the resources j/s components and I'm just gonna actually duplicate this complete lesson component we're gonna rewrite most of this anyway
but let's go ahead and just start with something instead of starting totally from scratch so let's say YouTube iframe that's what I'm gonna call this component and let's go ahead and delete
everything that's inside of here and let's start it fresh div let's just give it a class and simply because if ever I need to hook into it it'll be nice to have a class name for that and then
inside of here is where I'll actually have this YouTube now we immediately run into an issue which is of course we don't have blade inside view bold tackle that in just a second for my props let
me go ahead and clean this out let me clean out all of my methods here and computer properties I'll do the same all right so this is what we end up with this is our starting point for this
YouTube iframe all right so how do we get the lesson path well the best thing we could do is probably just pass in the entire lesson instead of just trying to pass it in the path we have a nice way
for laravel to pass in an entire model as a JSON object so let's take that approach but before we get to that of course this view component is not registered with
our app we need to register it so let's go back here and in our component section let's register a new component for YouTube iframe and of course we're going to require that out of YouTube
iframe that view so with that we've of course added that into our app that j/s now you saw the compiler fail and if we go back here into the terminal of course we are failing at that point where we're
trying to do the blade syntax but let's go ahead and fix that now let me go to my show view and instead of having that iframe I'm gonna delete that all together let's go ahead and add what we
actually need so what we have is YouTube iframe that's what we're gonna have and then what do we do to pass in that object like I said well we can simply say lesson equals and then we can
actually just pass in the entire lesson like so now we do need to bind this and when we bind this that's what's gonna tell view hey this is actually an object not just a string so we're gonna bind a
lesson into our YouTube iframe and all we need to do is just output lesson whatever actually knows what to do yes you can actually even call the to JSON if you wanted to but it's not necessary
leather actually knows how to do this that's the nice thing about working with view and layer them now in our YouTube iframe component we need to accept the prop and the prop that we're going to
accept is lesson now lesson at this point is going to be an object so we can say this that lesson dot path and if we bind this now this is going to be referring to this of course and then
lesson is going to be referring to the prop that we're passing in but the prop that we are passing in through here is an entire model not just one particular piece of data so we can actually access
paths using this dot syntax of course this is just JavaScript stuff all right let me hit save now and if we did everything right back in chrome we should basically get the exact same
thing and we do our video is still working but this time now we are wrapping all of this inside its own component so how cool is that now what's next well we
have that event now in view to grab an event we use the add syntax and we have that ended event if you recall if we go back here we do have this section down here for events and the one that we are
interested in again is the end at one so let me go ahead and just do a quick alert so when ended what we need to do here is actually call a method let's just call it lesson end it and then in
my methods let's create a new one called a lesson end it so when lesson end it gets called what do we need to do I'm just going to alert ended just to prove that it works all
right let's give this a go I'm gonna hit refresh one more time here I'm gonna hit the video and of course let's just go ahead and skip to the very ending of this video and if we did everything
right the video ends and of course we do get this alert the ended alert great so we are actually getting notified when the video ends so when the video ends that event gets triggered and then we're
gonna trigger this method right here now I have another component which is this complete lesson component now this is the component that you see down here this mark as complete component so if we
look down here there's this submit method on it and what it does is it does an access post to slash complete and then with the lesson ID we're able to actually mark the lesson as complete if
we take a look on my route file web page P we go down here to complete lesson there we go and we're hitting this complete lessons controller now the thing about complete lessons controller
let me show you is that it actually uses a method of toggle so what it does it's a many to many relationship between a user and a lesson called completed so it toggles the relationship in and out so
every time you hit that endpoint if that lesson was already marked as completed then what it will do is uncomplete it and it will also do that in if it hasn't been completed yet it will
complete it now this functionality is not really going to work anymore and the reason is that whenever the video ends of course we want to complete the lesson so if the user had never
completed the lesson before it will work but what will actually happen is that if the person had completed that lesson previously then it will toggle it which means that it will uncomplete the lesson
and that's not the functionality that we want so we're gonna have to do a little bit of refactor here in order to make that work and what I'm going to do is I'm actually going to create a whole new
entire controller for unn completing lessons essentially dividing that into two completely separate controllers so let's do something in this controller all I really need to do here is sync
without detaching so sync without detaching what it will do is actually make sure that our lesson is completed now the nice thing would sink without detaching is that it will work whether
the lesson has been completed before or not because if we ran sync only well it will do is it will only complete this one lesson and we don't want that we don't want to replace any other
completions but rather we want to make sure that this one is attached so will you sync without detaching then I'm going to actually save as this file and then call it uncomplete lesson
controller I'm gonna hit OK and we're gonna have a whole new controller here called uncomplete lessons controller so in the inverse action what are we going to do well we're gonna detach that's all
we need to do we need to make sure that we detach that lesson and so now we have two separate controllers one for attaching lessons and one for detaching lessons so we need to do one more change
and that is of course in my routes we need to create a whole new route and let's call it uncomplete lesson and then of course now we're gonna be calling the uncomplete lessons controller in my
original complete lesson view we can no longer just hit complete because that's only ever going to attach a lesson we need to toggle in our view between completing and earned completing
so what we can do is I have this status variable and status when status is equal to one it means the lesson is completed so we need to hit the incomplete and vice versa whenever status is equal to
zero so here's what we can do let's do let action we're going to create this variable and what we're going to say is this status so if this status is true in that case we're going to hit the
uncomplete but if it's false then we need to hit complete so I will actually replace this hard-coded completes for this new action does that make sense so we're gonna set this action equal to the
opposite of what needs to happen if we need to uncomplete the lesson then of course we're gonna hit slash uncomplete slash and then the lesson ID then if we need to complete the lesson then of
course we're gonna hit slash complete so this makes it dynamic that way we are toggling between those two things so let's go back here to Chrome and let's just make sure that that is still
working so right now I'm gonna mark this lesson as complete okay so it looks like it got marked as complete and if we go back to all lessons yes it was completed all right
now let's mark it as incomplete and let's go back to all lessons and yes it's not marked that's completed awesome so that is still working so that's gonna help us because now we have a place for
lesson ended to actually hit and so all we need to do in here is if we come back to completed lesson is basically copy this axis right here so all we need to do is hit slash and in this case I don't
need it to be dynamic because I know whenever the video ends I'm always going to want to complete but because we used that sync without detaching we're not gonna have a bunch of duplicates for
completions in our database we're just gonna have the one so this lesson ID how do we get the lessons ID well if you recall we have the entire lesson so all we really
need is just to grab the ID so we can grab this that lesson dot ID because remember we have the entire model that's the nice thing about passing in the entire model into our view so after the
response has been done well we don't really need to do anything so we're just gonna go ahead and comment that out now of course you're gonna see what's gonna actually happen and we are gonna want to
do something but for now this code will work and so we have a nice working example of this let me go back to Chrome and I'm gonna hit one of these lessons and I will actually attempt to complete
the lesson without hitting the button so let me skip over to the ending let's give it a couple of seconds to finish and there it is the lesson completed now notice I have not hit that mark as
complete I'm gonna head back to all lessons and sure enough that lesson is completed let's do the same with this other one just to prove that it works hit play skip to the very ending wait
for it to finish there it is it just finished back to all lessons and that one is also completed awesome good job so that is actually working we have one small issue though check this out if you
look down here right at the mark as completed whenever the video ends I kind of expect that to say mark as incomplete because well it doesn't make sense for it to continue to say that so if we go
to the end right the video ends now we know this lesson has been completed but yet we still see this as mark as completed but if we hit refresh now it says mark as incomplete so that
UI is not quite working we need to let that other component know hey you know what this lesson just got completed in another component so what we need to do is actually fire an event but we're
gonna run into a bit of an issue because when the axis completes yes I can say this omit and let's just call it lesson complete we can do that but if you recall back in
my show view so this component would be the one that's firing the events but this is the component that we actually need it to receive the event and that's not quite gonna work and the reason why
that's not going to work is because the only thing that we have connecting these two is our parent view instance and we don't really want to mess with the parent view instance so we have a couple
of different options yes we could actually wrap both of them inside a view component and but that's gonna bring in a couple of different issues and mostly what its gonna do is that we have all of
this blade syntax stuff here that is gonna be very difficult to replace with view it's gonna cause a lot of headaches for us to actually be able to do that whenever you're transferring from blade
into components of course everything needs to be provided to the component and you no longer have things like a guest we don't have the ability to check if a user is signed in or not so that
would complicate everything tremendously if we try to wrap this whole entire thing in a view component it would be almost impossible to replicate but there is a nice solution for this and it is
something that I actually learned not too long ago so I want to share it with you so what we're gonna do is something called view portals so view portals will allow you to have code and place it
somewhere else it's actually quite cool so this is the way it works now this animation here kind of gives you a glimpse of what portal view will do so this would actually allow us to have a
portal think of a portal as a black hole from our component we can actually have a destination that is outside of our component so the way that it would work is that we would instead of having
complete lesson here we would actually have a portal basically just a place for us to target and then inside our YouTube iframe we can actually have complete lesson so it would look
something like if we cut this out and we brought it inside that YouTube iframe if we put that down here of course right now that would render right after this but a portal will actually allow us to
push this into a separate part of our view it's pretty cool let's get started with it and I think you'll kind of understand how it works so let's go ahead and install it very similar to how
we did with the YouTube so let's just go ahead and install that and while that is running of course we got to do the exact same thing we're gonna import portal view and then we're gonna use it so if
you remember of course that goes in our app that jas file right here and we already have YouTube so let's go ahead and add another line for portal view now let's go ahead and just add the
semicolons not necessary but I do like the way they look so now we have this portal view so let's check out the documentation so here's this simple example you're gonna have this portal
destination and all this is is just a named destination then somewhere else in your code not even inside the same component you're gonna have this portal target and the name is gonna match the
target of over here so let's go ahead and try that now so we're gonna have a portal – target and then we need to give it a name where does that go well that's gonna go inside our show where our
completed lesson component used to sit of course we're gonna replace that with this new portal target and we need to give it a name and let's just call it complete lesson so now we have the
target but now of course we need to have the actual source so let's jump back to YouTube iframe and let's actually take this and let's wrap it inside a portal so inside this portal will put our
complete lesson and then of course we need to set the target now the target is gonna match the exact same name that we named over here so complete lesson so let's go back and let's name that
complete lesson all right so we're gonna have to do a couple of modifications here of course we were using blade before so we don't have access to these anymore so we need the
lesson ID well that's simple we already fix this so let's say this the lesson dot ID and let me go ahead and bind that and then we need a status so the status is the initial status of the lesson
meaning has the user completed this lesson now in order for us to actually be able to do that we need blade and we need PHP so that's not gonna work but here's what we can do is of course into
my YouTube iframe I still have access to plate I can actually bring this out into where I do have access to blade and then I can pass status into my YouTube iframe and then my YouTube iframe of course can
accept status as a prop and then we can simply just pass it through we could just say this that status we can pass that right on through into our complete lesson and with that we've brought that
in now if we did everything correct we should actually not see any changes at all let's hit refresh and sure enough check that out we have mark as incomplete and if we hit that now it
says complete and that is working perfectly fine but now that is using a portal how cool is that I think it's an unbelievable way for us to still integrate back-end with front-end using
view now I know it's a little bit of an advanced topic but I think that once you kind of see it working I think it starts to make sense again all we're doing is opening this target the target is where
your code is eventually gonna end up in remember that view uses a virtual DOM and a virtual DOM is capable of basically doing anything you want so there's no reason why that complete
lesson actually needs to sit there we can put it somewhere else such as inside our YouTube iframe and inside of there we can have a portal to complete lesson and then we have access to that now the
nice thing with this is that once we end we can actually change the status now this is gonna give us an error because it's a prop that's being passed in we'll fix that in just a
second but when the video completes we can say this status and then you can just set that equal to one because remember one means that it is completed so no matter what status was originally
we can just set that to one and I think that now this will fix our issue let's go back to Chrome and let's look for a lesson that has not been completed how about this one right here so this of
course says down here it says mark as complete let's go ahead and play this video get to the ending keep paying attention down here and let's see if we can get this to work so I'm gonna hit
down here at the end lesson ends and check that out it is now marked as incomplete so it's working everything is good but if we check out the console we
should have an error and there it is and the error that we're getting is simply that we are actually changing a prop directly view doesn't want you to do that what's happening is that these
props that are passed in are considered immutable meaning that you're not supposed to change them so to fix that what we can actually do is have our own data object and in our data object we
can actually have our very own version of the same thing that way we can change status let's set it to something like current status and then initially this is just gonna be equal to this status so
my current status is just gonna point to status initially but then we can actually change current status instead of this status current status what we're gonna pass in is not this status but
this current status and I think that'll fix it for us let me hit refresh now notice that this lesson is already completed so let's pick a new lesson maybe this one
pay attention down here again Marcus completed and let me go ahead and open up the console to see if we get any errors let me clear it out alright let's play that video let's get
to the end skip to the end and there we go the lesson ended we marked it as completed and we did not get an error so now when we go back then of course that lesson is completed so how cool is that
we learned a lot in this lesson we used a portal we created a new component there was a lot of advanced stuff in this episode but again in this series I just want to take you behind the scenes
so that you see how a real production app gets created and then you can actually go into the website and try it out so if you don't have an account yet make sure you head over to coders tape
comm and in here you can check out all of the things that we've been working on on our website now by the time that you see this video of course this feature will already be implemented and so
you'll be able to mark your lessons as complete without even having to hit the button so with that that's it for today's episode I hope you're enjoying this format as always if you have any
questions drop them in the comments below my name is victor for coders tape thanks for watching
Continuing in this series, today we are adding the ability of lessons to be marked as completed when the video ends. To do this, we are going to need to switch the way that we embed the YouTube video and start using a dedicated package. Once that is setup, we are going to find a way to not abandon Laravel Blade when using Vue through the use of Portal Vue.
For the best experience, follow along in our interactive school at https://www.coderstape.com
DigitalOcean Referral
https://m.do.co/c/7dce5364ef4d
Resources
Course Source Code
https://github.com/coderstape/library
Hit us up on Twitter with any questions or comments @codertape (https://twitter.com/CodersTape)
About This Course
Come along for the ride as we work on a real-world app for coderstape.com. We will be adding features and fixing some bugs.