Lesson Description
The "Create a Data Service" Lesson is part of the full, Intermediate Angular: Signals & Dependency Injection course featured in this preview video. Here's what you'd learn in this lesson:
Alex uses HTTPResource to fetch and manage backend data with automatic tracking of request status, like loading or error. He demonstrates creating a singleton service to query events from an API, passing a query signal to dynamically fetch filtered data, and handling the resource's value safely in the UI with Angular's new for loop syntax and tracking optimizations.
Transcript from the "Create a Data Service" Lesson
[00:00:00]
>> Alex Okrushko: OK, so now we have the app that talks parent-child, talks to each other, but we don't have the data yet, so let's start fixing that. Let's start utilizing our APIs. So I'm going to show you how to use a new concept in Angular. It's called resource in general and HTTP resource in particular. HTTP resource allows us to read the data from the backend and basically making that not only about fetching the values, but also be aware of the status of that request.
[00:00:45]
So if you heard of concepts like server cache or TanStack Query, RTK Query, React Query, basically a lot of the queries, the idea is that you tie the state on the frontend to the state on the backend. Right, so it's basically that server cache bridge, and then you are also aware of the request status itself.
[00:01:16]
Is it loading, is it error, does it have a value? So that is the basic concept. A resource has a general API like that. HTTP resource is using the HTTP client under the hood to make those requests. So let's start by creating our first service. In the app section here, I'll create the folder that I'll call core, and then in core, I'll create the new file which I'll call events service.
[00:01:57]
All right, so this event service, what we're going to have, so this event service export class. Again, we use services as classes, we create them as classes, events service, right, so we have this class. This class is injectable. Why is it injectable? We want to be able to inject this service to our components to do some interactions.
[00:02:33]
So in order for us to be able to inject it, we need to have it an injectable. Moreover, this class, we only want to have a single instance of it throughout the entire application. In our case, our service is even stateless, it doesn't have any additional state that it keeps track of. So it's even better, but anyhow, in this case, we'll just provide it in root, so it's a singleton throughout our application.
[00:03:14]
All right, so now we need to have a query. We want to bring this data to our event list page by calling the APIs. So the way we'll do it is, say we have readonly like events, right? And now we want to call the API for this, so we'll use the HTTP resource for it. And in this resource, I'm going to, first of all, let me just declare my private API URL here that I know what exactly I'm invoking.
[00:04:05]
And again, just be localhost at 3000. Right, this is our backend that's running here. And we're going to be specifically querying for the events, right? Again, our database here, events, so that's what we're going to be querying. So we have this API URL. And now in the resource we can say, hey, we can bring this API URL.
[00:04:55]
So I need to have a string. All right, let's do the interpolation here. Plus some kind of query. So how can I have this query? Query, right, so now what it would do is our HTTP resource would listen for this query, and the query is a signal. And whenever it changes, it's going to go and fetch this data from the backend.
[00:05:41]
The events themselves, we just do this just to show you. These events themselves have a few things. It has is it loading, it has is there an error, right? And again, this basically gives us the resource ref, this one's particular HTTP resource ref, and it can give us all the status, or it can also give us the value.
[00:06:11]
Right. At this point, the value is unknown because we didn't provide it, it doesn't know what kind of thing you're returning from the backend. So what we can do in this case is we can import our model that we have, right, for events. So let's utilize this and it'll be a DevFest event array. That's what we're getting back.
[00:06:44]
Right, that's what we're getting back. So now I can see the value, it knows that it's undefined or the DevFest event array. Right, so that's how it knows how to do it. And again, more importantly, it will link to the signal, and every time it changes, it will fetch the new data. The way it does it, it also aborts any previous request if there is one in flight, which is sometimes what you want, sometimes not what you want.
[00:07:24]
But again, at this point, we cannot control that strategy. I'll show you some advanced techniques where we can in the advanced workshop, but at this point we cannot control it, so we'll read whatever it is, and then if there's a new request, if the signal value changed, you'll send the new one and canceling this altogether.
[00:07:53]
All right, so once again, like we've seen with computed or linked signal, it's implicitly tracking the signal. All right, but obviously we don't have this query here, we have this query in our event list, right? We have this query here, so we need to pass this query signal to the service, so how do we do that?
[00:08:34]
Any ideas how do we do that? We'll create a function, right? And this function will say get events resource. And then we'll have this query, and this is the signal query. We don't really need to know that it's writable because we're not really, writable signal fulfills the signal as well. It's just a signal of a string.
[00:09:02]
All right, and then within this, now we have something we can attach to. So I'm going to move it here. This is events. I'm going to return this whole thing altogether. And then now we have this query that we're attaching to, making sure we have all the parentheses in place, cool. The only difference we want to do here is if there's no query, the query is empty, we don't want to touch the query, we just do the API call directly.
[00:09:50]
And let me just show you something here. So if we have this query here, and we'll check, so instead of returning the whole thing, we'll just first have this function body and then we'll return. So if we have this query, we'll just do return. If we have this query, then add this query to the request. Otherwise, just call this API URL directly, so it means we get everything, we don't do any filtering.
[00:10:27]
There's a little problem with the way it's written right now, if anybody can see the problem. Let me just, let's just use this API, but we're going to, there's a problem here which we need to address. If you see it right now, tell me. For now, we're just going to address it in a second. So we need to inject the service in this event list, and I typically inject things first thing in the component.
[00:11:03]
It's up to you if you want to have inputs first or inject first. I think inject kind of works better. So we'll have readonly events service here that we'll inject, we're going to use the inject function for this. We're not using injection through constructor anymore. That way might still work, but it's considered to be a deprecated pattern.
[00:11:33]
There are many reasons for this, and this inject function revolutionized how things are built for Angular, because now you can have functions that have injection inside of them. You no longer need classes for certain things. For example, we're going to look at the auth guard or many other libraries, and Angular included, were really affected by this.
[00:12:02]
Now we can inject things directly into the functions, which is amazing. You don't need a class for that. Yes. So did you share the variable, the signal variable without the service? Because what you just did now, yes, not yet. So right now I'm just injecting the service. And at this point, I would say, hey, my events, which again, I'll just do readonly events, I'll have my, and they are this event service, get the event resource, and I'm going to pass my search query to it.
[00:12:54]
So this way my search query is now passed to HTTP resource. There it is. So now it's passed. OK. And we can see here, but still there's a problem. So if you spotted, great. If not, I'm going to highlight this because sometimes when you do your own thing, you might run into this. And look, everything's compiling fine, no errors in the template.
[00:13:30]
But let's try to find for Angular here, for example. I can see nothing's changing, or why nothing's changing. Maybe refresh the page, no. Nothing's changing. Why is nothing changing? All right, you check the requests, and we see that there's no new requests coming in. No new requests, what's going on? We passed it, so see how we destructured, basically read the value from the signal outside of HTTP resource.
[00:14:02]
So resource, that's the first query, just finds it, reads the value, cool, read the value. Now we're changing the signal value. But the resource is not automatically rerun, and this is the same with computed, the same with linked signal, the same, wherever we have this implicit tracking, we need to make sure that's in the body of that callback, right?
[00:14:41]
So now, if we move this from here to here, the way I copied it, it's fine. I just move it like this. Now it is within the resource HTTP resource body, and now it knows it tracks it, just changed as well, so let's see if that works now. If not, that'll be very interesting. So we'll just do Angular. Angular, do we pass, do we not pass?
[00:15:02]
Hold on. Let's see what we doing, query, query, query, the API request. Oh yeah, so we're not returning anything yet. You know why we're not returning it yet? I jumped the bullet, so this one, let me just pull this out again, just to see the difference. We are reading the value, but we're not using the values yet, so we're just showing the fake data that we had before.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops