Angular for Workflow Processes
In this article, I describe a state transitions technique for developing an Angular timesheet application that involves a workflow process.
Join the DZone community and get the full member experience.
Join For FreeAngular provides an excellent platform using which we can develop complex UI applications like workflow process management. In this article, I describe a state transitions technique for developing an Angular timesheet application that involves a workflow process. A timesheet submission and approval workflow process is considered as an example to illustrate the technique.
It is possible to quickly develop an Angular timesheet application starting from a routes configuration like:
const appRoutes: Routes = [
{ path: 'timesheet', component: TimesheetComponent },
{ path: '', redirectTo: '/timesheet', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
]
Where the TimesheetComponent displays the timesheet form with buttons like "Submit," "Approve," and "Accept." When the employees access the /timesheet link, they would see just the "Submit" button; when the managers access the /timesheet link, they would see the "Approve" button, etc. Clearly, the TimesheetComponent becomes heavy-weight, handling all the functionalities.
When workflow error paths are added to the application, the complexity of the TimesheetComponent would increase much higher. In the next section, I describe a state transitions-based technique that helps in writing more maintainable and easily extendable Angular code.
State Transitions
Let us now transform the above requirements as state transitions like:
UNKNOWN | empTimesheet | loadEmpTs() | loadEmpTsSuccess | EMPTSLOADED |
EMPTSLOADED | submitTimesheet | processSubmitTs() | submitTsSuccess | TSSUBMITTED |
TSSUBMITTED | mgrTimesheet | loadMgrTs() | loadMgrTsSuccess | MGRTSLOADED |
MGRTSLOADED | approveTimesheet | processApproveTs() | approveTsSuccess | TSAPPROVED |
TSAPPROVED | hrTimesheet | loadHrTs() | loadHrTsSuccess | HRTSLOADED |
HRTSLOADED | acceptTimesheet | processAcceptTs() | acceptTsSuccess | TSACCEPTED |
Where all the state transitions follow a pattern like - Initial state > Pre-Event (or trigger) > processor (or action) -> Post-Event > Final State. To keep the discussion brief, I have not included the sign-in process and workflow error paths in the above transitions.
We can then set up the routes in the app-routing.module.ts like:
const appRoutes: Routes = [
{ path: 'acceptTimesheet', component: ProcessAcceptTimesheetComponent },
{ path: 'hrTimesheet', component: HRTimesheetComponent },
{ path: 'approveTimesheet', component: ProcessApproveTimesheetComponent },
{ path: 'managerTimesheet', component: ManagerTimesheetComponent },
{ path: 'submitTimesheet', component: ProcessSubmitTimesheetComponent },
{ path: 'employeeTimesheet', component: EmployeeTimesheetComponent },
{ path: 'timesheet', component: TimesheetComponent },
{ path: '', redirectTo: '/timesheet', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
]
Where the TimesheetComponent loads <employee-timesheet></employee-timesheet> or <manager-timesheet></manager-timesheet> or <hr-timesheet></hr-timesheet> depending on the role of the signed-in user and after validating the timesheet state (TSSUBMITTED, TSAPPROVED, and TSACCEPTED which are typically stored in a backend DB). Note that the routes employeeTimesheet, managerTimesheet, and hrTimesheet are shown above for illustration purposes, and they can be removed.
So we see that each of the components above is very lightweight, and each one handles just one task. Any new feature that may need to be added (like the manager returns the timesheet for corrections etc.) can be handled by adding one or more new state transitions. A starter implementation of this workflow can be found here.
Next Steps
Readers who are interested in exploring more on these ideas more can take a look at this GitHub project which expands on the ideas presented here.
Conclusion
It is shown that by using the state transitions approach, we are able to generate Angular code that is easily extendable and more maintainable than the conventional approach.
Opinions expressed by DZone contributors are their own.
Comments