Time tracker code

Code session for the first application and library in NX.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Next-Level Angular Apps with NX course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Next-Level Angular Apps with NX, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Next-Level Angular Apps with NX
  • [00:00 - 00:20] I've jumped to my ID and our work today will start with a small cleanup. I want to remove some unnecessary code that I'm not going to use. So first of all, I'm going to Time Tracker, Assar C app, and I have app component HTML. I don't need that. So I'm going to remove it.

    [00:21 - 00:36] I'm not going to use welcome, annex welcome component that is a welcome component from an ex. Just remove it. Of course, you will need to fix all the references like here.

    [00:37 - 00:56] Yeah, so let's remove it. Our plan for the app is to have a really simple Time Tracker app. We will have an input for activity name. We will have two buttons to start and stop activity and list of past activities . So let's jump to our library that we have created previously.

    [00:57 - 01:08] And let's check what is inside. We have a simple component inside here. We will not use it. So I'm going to delete it.

    [01:09 - 01:32] Then I'm going to create a new file. I'm going to call it. I'm going to call it Time Tracker state service. So here we have our service file. Of course, it's an injectable.

    [01:33 - 01:51] Okay, so we have an empty service. I'm going to add necessary code and then I will walk you through it just to explain what I did. Our walkthrough will start with types that I defined. First one is activity that contains name and minutes.

    [01:52 - 02:07] And of course, I have multiple activities, so it's an array of activity. So then I have my class. I defined free fields. Two of them are private. One is private static grid only.

    [02:08 - 02:23] So first of all, I have activities as an array of current state activities. And I have activities with dollar sign at the end. It means that it is observable. So I have a replace subject.

    [02:24 - 02:36] And I'm going to keep it here just to make my activities reactive. So then I have a constructor and in constructor, I'm calling load from local storage.

    [02:37 - 02:51] So I keep my activities in local storage. So it will be restart from it every time when I refresh the page. So I have a local storage, get item. I'm using that third field that is private static grid only.

    [02:52 - 03:13] It's local storage key activities. And if there are some saved activities, I will try to parse the JSON and then send it to the stream. I have two more methods here. So I have add to add a new activity that takes name and minutes.

    [03:14 - 03:29] And I'm pushing to activities to my current state and then on the stream. And of course, I need to save it in local storage every time when I add something. And I have a very simple get method that is basically returning that stream as observation.

    [03:30 - 03:41] And that's all. It is that simple. Now I need to fix my index.js file in the library. So of course, I need to remove that component that I previously removed.

    [03:42 - 03:54] And I need to export my service. So right now it's exported and I can use it outside of my library. And remember that everything that you have in index.js is public.

    [03:55 - 04:04] So your colleagues, other developers will be able to import it and do that. If you want to have something that is private, just don't export it from index.

    [04:05 - 04:18] ts. Let's go back to our app component. Once again, I will save you sometime watching me how I type the component. Then I walk you through all the code that I wrote and I will explain what I did here.

    [04:19 - 04:28] Okay, I have all the codes. So let's start with HTML file. So as you can see, we have an input to put our activity name. We have two buttons as we planned.

    [04:29 - 04:41] We have a start and stop button that calls start and stop methods. And we have a list with ng4 off with Async pipe here, a list of past activities .

    [04:42 - 04:56] So it's a very simple component. So let's go to the TS file. As you can see, I have my time tracker state service injected using inject function.

    [04:57 - 05:10] I have a view child to my input element just to read the current value of that input. I have a private variable date started and I'm saving here the current date when user is clicking that start button.

    [05:11 - 05:18] So here we have a start method. It's a very simple method. And of course we have a stop method here.

    [05:19 - 05:27] So of course, if there is no date start that you cannot stop if you haven't started. So I'm alerting user that you cannot stop.

    [05:28 - 05:44] Then I'm calculating the difference in minutes between start and end date between clicking on start and stop buttons. And get minutes is a very simple private method. So first of all, I'm creating a new date to get the end date.

    [05:45 - 05:58] And then I'm calculating difference in minutes. When I have minutes, I'm reading the current value of input elements of my input in HTML as a name.

    [05:59 - 06:07] And if there is no name, I'm alerting my user that name is not provided. And then I'm calling this state so my service add.

    [06:08 - 06:19] And you may wonder, okay, we have add where it's get, right? So if we go back to the HTML file here, we will see that I'm using state directly here with AsyncPipe.

    [06:20 - 06:30] So it's very, very reactive and declarative way of writing Angular code. I have added a bit of CSS just to make it look a bit nicer.

    [06:31 - 06:45] It's still a very simple basic application. But, you know, if we can make something a bit prettier, why not? Before we go to our browser and check how it works, I want you to notice one thing.

    [06:46 - 06:55] So check how the import to our library looks like. It doesn't look like it is in the same repo. It looks like it is from npm packages, right?

    [06:56 - 07:14] And that's a huge advantage because you don't want to know where it is in the directory structure. You just want to use it. And you know that it is internal package because you're using that add time tracker prefix to say, yeah, it's mine package from this model repo.

    [07:15 - 07:27] Okay, I opened our application in the browser. As you can see, we have our input to buttons. So let's test it. Let's check our first scenario. So let's click on step button without activity name and without starting it.

    [07:28 - 07:36] It should alert us that we need to start some activity. So stop. And as you can see, we have alert that timer is not started.

    [07:37 - 07:56] So now let's try to start it. Then stop. We should have an alert saying that you have to type activity name. So stop. Name not provided. So that's correct. And the last check, let's add some activity name. So my activity and then stop.

    [07:57 - 08:13] And our activity is here with zero minutes because, you know, we did it very fast. So let's try to add another activity. So let's start and stop. We have second activity.

    [08:14 - 08:27] And now I will add the third activity and I will wait for some time just to check if that minutes calculation works. So see you in a second. And as you can see, one minute past. So it is working.

    [08:28 - 08:39] And with these simple steps, we have our first Angular application using an X- monorepo with proper application and proper library that we imported in our application.