By Chase Baker
I’ve been in software development for around a year and a half, mostly in the front-end of development. In that time I have become very accustomed to Angular, one of the most popular front-end frameworks, and with Angular comes Reactive Forms. When I first heard about reactive forms compared to template-driven, I was pretty confused but after completing a complicated and very involved reactive form for a timesheet, I felt much more confident with them.
This post comes with the assumption that you have somewhat of an understanding of Angular and Reactive Forms.
Alright, so where to start?
First, we need to import everything needed for the form in the component.ts file.
Let’s create our forms.
You’ll notice that I’ve created three different forms. One ‘master form’ (timesheetForm) and two ‘child forms’ (projectForm and adminForm). I do this to make things easier down the road but more on that later.
projectTime and adminTime will contain large objects with arrays inside. So to simplify things, I will separate them into their own components and send their form data back to the master form that resides in the parent component.
Adding data for the forms.
I call a service I’ve created to retrieve the data needed for the form through an API. Once the data is retrieved, I then use the method patchValues() to add the data directly into the created timesheetForm.
At this point, I’ve created the master or ‘parent form’ that will exist in the parent component. The three components will be the timesheet-submit component, admin-timesheet component, and project-timesheet component.
Here are 2 methods we will need to add the data from the child forms when they are updated by the user.
Each of these are listening for the $event coming from their respective child components, so once an $event occurs it will run the function to grab the new form data collected in the child component form and update or insert it into the master form.
Now in the child component project-timesheet, I will have a similar process of creating a form.
— I won’t be going into detail about the adminForm due to the process being the same. —
projectTime will be created as an empty FormArray. We will set projectTimesheet to the data from projectTime. Now I can use the method addProjects() to loop through and add each individual ‘project’ to the form array. This way the user can access each different project as its own miniature form when they need to make changes.
If you think it’s already deeply nested, we are about to go even deeper into the form. The form control hoursHashMap contains its own array of objects that represent each day containing another set of FormControls or FormGroups like comments, hours, day, open, and another array of objects named tasks to represent each day’s tasks. The tasks form control will contain another form but we will get into that later.
If you haven’t already noticed I like to use methods to do the work for me when creating each form control that is an array. That’s where initHoursHashMap() comes in. Otherwise, this form would be very long and taking up more room in the ts file, making it harder to read. Parameter 1 is the data that was retrieved from the API and parameter 2 is the day of the week that I have pre-set in another component.
Now I’ll use the method initDayTaskInfo() and pass in the needed data for each day of the week and then return the data back to the form.
Each day of the week has its own tasks so we need to create the form controls for those. I’ve created a small form called taskArray that will belong to the tasks form control above. Using a simple forLoop, I loop through the tasks and add each as their own group back to the array tasksArray. Now each task can be edited on their own. Think of this part of the timesheet being where the user will create a 2-hour work-related task ex. (Deployed Application, 2 hours, comments about the task). Remember this is creating the form and adding any existing data if there is any.
Here is what the html will like for the project timesheet. I have the formGroup ‘projectForm’ at the top level, inside of the projectForm element we can get into the formArray ‘projectTime’. For that we will need to loop through the controls, creating a new formGroupName of ‘I’ for each project. Then within that formGroup will contain another formGroup ‘hoursHashMap’ that contains the seven formGroups for each day of the week. the hoursHashMap object contains the info for each days tasks (comments, hours, task name ect.).
I’ve created a modal that opens when the user wants to add a task to a certain day. So with that, I need to send the data to the modal that correlates with that day. Once the user adds/updates new data to the modal and closes it, the results will be sent to the taskForm.
Here is the input modal html for each days task data using *ngFor to loop through the form controls.
Setting up the logic for the modal will start the same as any other component. We will need to add our imports and create any needed variables, with this being a modal I’ve injected the data through the constructor using Angular’s built in MAT_DIALOG DATA service.
Notice in ngOnIt() I have four functions, as the names suggest, I will set the data from the parent, create the form, patch the values and check for any existing data in the session storage or backend database.
The setDataFromParent() function is just taking the data injected when the modal was opened and assigning them to new variables, it also creates a key I will use for sessionStorage. The patchValues() function is what will actually be taking the data and setting it at the form controls of taskForm.
Then what I did was create a function for checking for data wether it is coming from the backend database or session storage from the user. I created a storageKey from the projectDesc and the dayOfWeek making each days task unique.
And of course we create the form for the task.
In regard to the onChanges method, it will update whenever changes are made to the form. What it is doing is updating the total hours the user is adding/removing from each project and it sends the form data to the parent component which will contain the master form.
The setWeekTotals method is needed to set the original total amount of hours for each project when the page loads and has that initial set of data.
Finally our Timesheet,
Project One and Project Two will populate with any existing data if there is any, otherwise they will start as an empty form. Each day has it’s own input for the amount of hours worked that day, then once the button is clicked the modal will pop-up for the user to input the task data for that day.
In summary I’ve created a in depth Timesheet form with a lot of moving parts. Reactive forms make it much easier to handle the logic on the component side of things. If you have a form that is filled with multiple arrays and objects like this one I highly recommend using Reactive Forms. I hope that my demonstration has helped and thank you for reading.