Goal: Dynamic Range Graphs0:00
Next up, let's figure out how to make our graphs more dynamic. So for example, what if we could introduce this range functionality? So we default to 100 days back, but if you change this, it will re-render the graph. Okay, we haven't built any of this, so let's get started. Now, we're going to rewind just a little bit. I think it's really important to learn how to do something and then do it again, and again, and again, until you fully understand every little piece. So take a look at what I have so far. Here's where we're going to start. So we import Vue and VueResource, like we learned in the last lesson,
Here's where we're going to start. So we import Vue and VueResource, like we learned in the last lesson, and then I build up my Vue instance, but we haven't referenced our GraphComponent yet. If we take a look at that, once again, very similar to what we've worked on in the last couple of videos. So we have a base template, we accept a URL, we have some data for the chart and legend, but that's it. We haven't done anything where we fetch the data from our server. We'll rewrite that part again in this lesson. All right, so let's get started.
Creating RevenueGraph Component0:58
We'll rewrite that part again in this lesson. All right, so let's get started. I'm going back to my Welcome.vue. So here it's empty, but now we want to display our graph. However, I've decided this revenueGraph is going to be specific. We're not just charting some data, we're also going to have some toggles, like a span, where I can say, no, I only want the last five days. So with that in mind, it sounds like I need a custom component here, in which case I'll call it RevenueGraph. Next, just like we did before, we need to give it a URL.
in which case I'll call it RevenueGraph. Next, just like we did before, we need to give it a URL. And in this case, it'll be API/revenue. Okay, so let's go ahead and create that. Resources/assets/js/components/RevenueGraph. So this will be a child it will inherit from the parent Graph. Okay, so let's import the Graph. It's in the same file. And then I can say export default Graph.extend. And that way we inherit all of the functionality that we defined here.
Fetching and Rendering Chart2:23
Well, let's think about it. Before we write any code, just figure out in your head what's going on. Well, we fetch the data from the server, and then we render the graph. That's basically what we're doing. So let's write that out. This fetchData, and then receive the response and render the graph. And remember, the response, if we actually want the data off of the response, we reference response.data. Nice and readable, right? We can get rid of that and move that onto its own line.
Nice and readable, right? We can get rid of that and move that onto its own line. Okay, so let's flesh this out a bit more. How do we fetch the data? Well, we make an AJAX request. This HTTP::get. Now, what about the URL? Well, remember, you pass that in as a property. So I will reference that here. Next, how do we render the graph?
So I will reference that here. Next, how do we render the graph? Let's create that. This will receive the data. And now this part will be exactly the same as even what you learned in the first lesson. We say this.chart equals a new Chart. And remember, we imported the chart.js library at the top. Now next, we have to find the canvas. And notice we can track it down right here. this.else.canvas.
We have the data sets. In this case, we're still hard coding a couple things. No problem there. That looks good. And this should all be familiar to you. Finally, now that we're done, we can generate the legend by saying this.legend equals this.chart.generateLegend(). OK. Look good? Let's go over it one more time.
Look good? Let's go over it one more time. So we have our main custom prop that accepts a URL. And then when the component has loaded and it's ready to go, we call this method here, which will fetch the data from the server. And when we have a response, we render the graph. We fetch the data with a simple AJAX request. And we render the graph by newing up the chart, fetching the canvas, starting a line graph, and passing in all of the appropriate values and colors for the data. Now, this looks good to me as a default.
Building Range Selector UI5:04
Now, don't forget, we should always have a single root node. That's a good practice. And then, well, let's see. Maybe we'll have some kind of label that says how many days. And then we'll have a select element. Now, how exactly do we bind to this? Like, we want to have maybe 355 different days you can select from. So with Vue, we could say, well, we want an option, but we're going to have many of them. So I will say v-for in 365 days, then echo out in.
them. So I will say v4 in and 365 days, then echo out in. That's a simple, easy way to go about this. Now, we'll come back and work on this a bit more, but that's fine for the time being. Finally, we need our canvas like we had before. So we'll have hard code width of 600 and height of 400. Finally, like always, we have to identify this. So I will call it canvas. And what else? Last step, echo out the legend as HTML.
And what else? Last step, echo out the legend as HTML. Now, the only remaining thing I see is why don't we ensure this is block? So this section comes on top of the canvas below. So yeah, I'll wrap all of that within a div here. OK, next up, what else is unique about this graph? Well, one thing is I want you to pass in a range as a custom property. So that way I can say, I want to display my revenue, but the range should be 10 days worth, something like that. So that's unique.
something like that. So that's unique. I need to allow for that. Props. And then we'll have a range that has a default of about 30 days. OK, so we still have more work to do. But why don't we start by prepping to view this in the browser? So now I can say, import RevenueGraph from components/revenue-graph. And then I can add that as a child component of our root view instance. OK, so I'm going to boot up gulp watch so we can keep an eye on changes.
OK, I'm guessing that we did not return. So back to our graph. We load it by saying this.fetchData. And yeah, we forgot to return. OK, that compiles down. If we give it another refresh. Once again, it's still not working, but we can see the canvas element. So we're getting there. Let's see what happened. Here's our revenue graph.
Let's see what happened. Here's our revenue graph. We have set the range and we do have the chart. So that looks OK. Let's take a look at the network request. Well, right now we're not returning anything. So that makes sense, right? All right, next step. Go to the routes file. And yes, I've removed that route entirely.
Adding Backend Range Query7:50
Go to the routes file. And yes, I've removed that route entirely. Well, now we know that we should expose this functionality where you can select the number of days or a span of days that you want to fetch revenue for. So with that in mind, let's try to write this out as readably as we can. How about performance within days or spanning? That might be good. Performance spanning days. And then we'll pass in 30 for now. We'll hard code that.
And then we'll pass in 30 for now. We'll hard code that. And then finally, like we did before, we will pluck only the values we care about right now. In this case, the revenue column as well as created_at. OK, it looks like I need to create that query scope. So over to Performance down here. method scopeSpanningDays. And that will accept the queryBuilder as well as the numberOfDays that we're passing in. In this case, 30. All right, so how do we do that?
In this case, 30. All right, so how do we do that? How do we add this constraint? Well, we could say query. And first things first, I want it to be oldest to newest. So I will tack that on here. Next, we could say only give me the records where the date and specifically the created_at date is equal to or actually is greater than or equal to. And then this would be the number of days ago. So you could use the DateTime object.
And then this would be the number of days ago. So you could use the DateTime object. You know, you may not know this, but you can always say new DateTime and then say like 30 days ago. That's pretty cool. But also we often use Carbon since we're used to it. So you could say Carbon::now()->subDays($days). And that would do the trick. All right. So at the top, we've already imported Carbon.
All right. So at the top, we've already imported Carbon. So we're good to go in that regard. And I think this looks good. Now, if we go back to the routes file, when we fetch the revenue, we find our performance records spanning the last 30 days and we pluck the revenue. So if I go back to Chrome now and I give this a refresh, there we go. We can see our graph. And here's what got returned from the server. But now a few things.
Binding Range and Reloading9:48
And here's what got returned from the server. But now a few things. First, there's still no connection between the select dropdown and the graph. They're not hooked up yet. So why don't we create a binding for that? I'm going to go back to my revenueGraph. And right here, I'll say v-model equals our range property. So now we are binding that by default to 30. Let's go back to Chrome. And that should say 30 when I refresh.
Yeah, and it does. So now we can see we set a default. But if you want to override it, you can pass the range property. So if I only want three records, that should work. Okay, so we have that part set up. But there's still no connection between this value and the request we make to the server. Now, we can do this in a couple ways. For example, back in our GraphComponent, remember, we don't want this parent component to be overly familiar with any specific type of graph. It just needs to be very generic.
But, of course, we don't want that in the root graph component. That should only exist on the RevenueGraph component. So now we have two choices. One, you could reference some kind of method like this. And then on your child component, you could create that method and return whatever needs to be passed there. Or if you want, you can just allow the child to override it when it needs to. So, for example, I would copy that, come back to my RevenueGraph, and then down here in my methods, I can paste that in. And now this implementation will take effect.
and then down here in my methods, I can paste that in. And now this implementation will take effect. And now we'll say, yeah, I need to pass through the range, which is equal to whatever we have here. OK, so take a look at this. Once again, we give it a refresh. And if we take a look at the network request right here, notice, yes, we did pass that through. range equals three. OK, so now if we take a look at the preview response,
Range equals three. OK, so now if we take a look at the preview response, we're still not factoring that into the query. But that's the easiest part. I could say right here, range equals request->range. Or once again, on the server end, we'll default to 30. And then I can pass that through. So fetch the range request parameter. And in this case, it would be three. But if you don't give me anything, I will default to three.
And in this case, it would be three. But if you don't give me anything, I will default to three and then pass that to our query scope. So now we should see exactly three records. And we do. Awesome. So now let's ensure that from our welcome view, we can reference the default. So now we should see 30. And we get a month's worth of records.
two days' worth of information. But nothing happens there. So how do we hook into that? Well, once again, think about it. We want to say when the user changes this select element, well, we should re-fetch that data from the server and re-render the graph. OK, so go back to revenueGraph right up here. And we say, when we change, I will reload my graph. Now, we could add the method right here.
And we say, when we change, I will reload my graph. Now, we could add the method right here. And in fact, let's do that for now. Reload the graph. So we reload by first. Well, let's find the chart and destroy it. Now, there's actually a number of ways to expand upon an existing graph. So for example, you can, using chart.js, add a number of points and then call an update method
So for example, you can, using chart.js, add a number of points and then call an update method that will dynamically update the graph. But also, if you just want entirely new data, what I generally do is destroy the chart and re-render it from scratch. Now, how do we reload it? Well, take a look. We already made this nice and convenient. We have this load method that fetches the data.
We already made this nice and convenient. We have this load method that fetches the data and renders the response. So that means I can just call this.load, and it should do the trick. Let's try it. Back to Chrome. Refresh. So we have our 30 days worth of data. We change it down to two.
So we have our 30 days worth of data. We change it down to two. And crap, it didn't work. Let's see. Nothing in the console. We must have a typo here. Let's debug it together. So here's my revenue graph. Select, v-model, chance, chance, change. Okay, I'm pretty sure that'll fix it.
or if you have a little more logic, maybe a little more to the template, you can extend that graph. And that's what we did in this case. We created a RevenueGraph where we changed the template. Now, we still inherit any of the default properties or data properties, but we can expand upon that. So notice here where we set props range. Well, we aren't overwriting everything. So we still have the URL prop.
Well, we aren't overwriting everything. So we still have the URL prop. And I'll prove it to you. Of course, it's working. But for further proof, yeah, we can still get the URL. So when you inherit from another component, you also inherit any of its properties or default data values. Anyways, if we come back here, now the only thing we had to do was modify how we fetch the data. The default is simply to make a GET request to the URL.
now the only thing we had to do was modify how we fetch the data. The default is simply to make a GET request to the URL. But if you ever need to do anything else, if you got to set a header or pass through some values, just override the single method, specify what the AJAX request should be, and once again, you're good to go. Finally, if you ever need to re-render the graph, you can just add a call to the reload method. And in this case, we're binding it to the change event.
you can just add a call to the reload method. And in this case, we're binding it to the change event. All right, that's all there is to it. I will post this code to GitHub. If you have any questions, as always, ask below the video.
