Share Data and Business Logic Throughout an Angular Application with Services

Sam Julien
InstructorSam Julien
Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 3 years ago

Right now, the collection of habits and the business logic for adding a habit are in the component. This works fine for how small our app is right now, but what if we need to access the collection of habits in another component? Or what if we need to add a habit somewhere else? We'd either have to duplicate code or come up with convoluted ways of passing data through inputs and outputs. This is what services are for in Angular. Services let us store data and logic in a class that we can reuse anywhere in our application.

Sam Julien: [0:00] Right now, we've got our habits array stored on our component here. That works OK for such a small application. We've also got our AddHabit logic here in our component.

[0:15] The problem is, our app is small right now, but what if we need to access this collection of habits somewhere else in our application, or what if we need to be able to add our habit somewhere else in our application? We'd have to duplicate that code or come up with weird ways of passing it around, and that's what services are for in angular.

[0:33] Let's go ahead and create a service that we can store the collection of habits, as well as the AddHabit logic. I'm just going to open a new terminal here, and we're going to do ng generate service. If you' d like, you could also shorten that to ng g s, for generate service, and we're going to call this habit for the habit service.

[0:59] Angular will generate a file for us and if I open up the file explorer, you can see that we have it over here, so I'll go ahead and open that up. Let's go ahead and create the service, implement everything and then we'll add it to our component.

[1:13] I'm going to go back over to the list component over here and first, let's just copy over our habits array and add that to the service. Then let's copy our AddHabit function here and add that as well. We can rename this to addHabit.

[1:37] Now, how are we going to enable components to get this collection of habits? Well, let's go ahead and write a method here called getHabits and what we're going to do is we're going to change this array into an observable.

[1:51] We could return the array straight up but let's change into an observable so that if we move to a real HTTP call, the component is already set up correctly. To do that, I'm going to import the of() creation method from RxJS and I'm going to say return of(this.habits).

[2:09] I'm also going to explicitly say that this return type is an Observable<any>. Your editor should help you import the Observable from 'rxjs'. We could give this a strict typing and that's a good idea but we're not going to do that for the sake of simplicity here.

[2:27] Our service is pretty much set up here. Let's go ahead and implement it in the habit list. The first thing we need to do is we can get rid of all of this. We still need to define this property. Let's go ahead and specify that it's a type of Observable<any>. Again, we've imported that up here. What we want to do is get the collection of habits when the component loads.

[2:52] To do this, we're going to need the OnInit interface. I'm going to say implements OnInit and import that. You can see that that is now imported from @angular/core and you could see that we have this spread squiggle because we're not implementing the interface correctly. What we need is the ngOnInit function. Luckily, TypeScript can help us out here with our editor.

[3:14] We're going to be defining the habits Observable here in this ngOnInit. That's where we're going to set that value. In order to do that, we first need to inject an instance of that habit service so that we have access to all of its methods.

[3:29] I'm going to say private habitService and inject or specify the type of HabitService that will then add that import up at the top of the file. In our ngOnInit, what we'll do is we're going to go ahead and call that getHabits method and subscribe to it.

[3:46] I'm going to save this.habitService.getHabits. We're going to say .subscribe since it's an observable. In that, we're going to say specify a function here of habits which we can then set our this.habits property = habits. Cool. If I just go ahead and comment this out and save it and open the browser to the side, you can see even if I refresh the page, we are now getting our habits from the service.

[4:14] Let's go ahead and use our addHabit method. I'll say this.habitService.addHabit and pass in the newHabit and open that to the side, and say Test, Add, and you can see that that's working. Great.

[4:30] Now, everything's working. There's one last thing that we can do to optimize this a little bit. Right now, we're manually subscribing to the getHabits observable here. If we do it this way, we would also need to remember to unsubscribe when the component is destroyed.

[4:46] There's a nicer way of doing this that Angular provides. We can use something called the async pipe. A pipe is a pure function that we can use to manipulate and transform data in the template. That's what we're going to do.

[5:00] Instead of doing this where we call getHabits and subscribe to it, what we're going to do is set this.habits = to that observable. We're going to get rid of the rest of this.

[5:12] Now, we can basically come over here to the template and give it the async pipe right here. We're telling Angular, "Hey, Angular, this is an observable, and subscribe to it, unsubscribe to it, do everything you need to do." Then we can still iterate in our ng4 here.

[5:31] If I open the browser to the side and just refresh, you can see that everything is still working. That's how to use your first service in angular to share both data and functionality throughout your application.

rubenfrancogarcia
rubenfrancogarcia
~ 3 years ago

sorry, Can't delete the first comment. But on line 12 on habit-list-component.ts file at the of keyword. I get the following error: Type 'Observable<any> | undefined' is not assignable to type 'NgIterable<any> | null | undefined'

rubenfrancogarcia
rubenfrancogarcia
~ 3 years ago

nvm, the async pipe solved it. My complier yells at me before that point so stopped the video, and I tried to fix it at that point.

Sam Julien
Sam Julieninstructor
~ 3 years ago

Glad you got it sorted!

Alfonso Rush
Alfonso Rush
~ 7 months ago

App breaks at this point.

Compiled with problems:
×
ERROR
src/app/habit-list/habit-list.component.ts:20:3 - error TS2564: Property 'habits' has no initializer and is not definitely assigned in the constructor.

20   habits: Observable<any>;
     ~~~~~~
ERROR
src/app/habit-list/habit-list.component.ts:28:14 - error TS7006: Parameter 'newHabit' implicitly has an 'any' type.

28   onAddHabit(newHabit) {
                ~~~~~~~~
ERROR
src/app/habit.service.ts:33:12 - error TS7006: Parameter 'newHabit' implicitly has an 'any' type.

33   addHabit(newHabit) {
              ~~~~~~~~
Markdown supported.
Become a member to join the discussionEnroll Today