Description
For this final assignment, students will work with an existing Angular application (ie: Assignment 5) and update it to allow users to edit data as well as to practice building and deploying their App to the cloud (Heroku). Note: This assignment relies on the successful completion of Assignment 5. If you require a fresh copy of Assignment 5, please email your Professor. Specification: For our updated Assignment 5 application (now Assignment 6) we will use our knowledge of Template Driven Angular Forms to allow users to edit employee / position information as well as add some search/filtering to our Employees table to make it more useable. Lastly, we will deploy it on Heroku. Getting Started: To begin this assignment, we will first need to make a copy of or current Assignment 5 and open it in Visual Studio Code. Once it is open, we can proceed to add new methods to our Employee & Position services (Part 1) NOTE: For Assignment 5, we didn’t address the issue of the background slider images, ie: the console errors that look like: images/slider/bg3.jpg Failed to load resource: the server responded with a status of 404 (Not Found) To fix these errors, simply open your home.component.html file and modify the 3 image paths (bg1.jpg, bg2.jpg & bg3.jpg) from: images/slider/… to /assets/images/slider/… This should give you your slider backgrounds back: Part 1 – New Functionality for Editing Employees / Positions Step 1 – Updating EmployeeService & PositionService For this assignment, we will enable users to edit existing employees & services. To enable this functionality, we must add some additional properites & methods to our EmployeeService & PositionService: EmployeeService (employee.service.ts) Before we can begin to update our EmployeeService, we must define a new class: EmployeeRaw in its own file (employeeRaw.ts) within the “data” folder. The EmployeeRaw class must have the following properties / types: Property Type _id string FirstName string LastName string AddressStreet string AddressState string AddressCity string AddressZip string PhoneNum string Extension number Position string HireDate string SalaryBonus number __v number Next, we must import our new EmployeeRaw class in our EmployeeService. This will allow us to create the following additional 2 methods: • saveEmployee(employee: EmployeeRaw) This method must make a “put” request (using the HTTPClient module) to your Teams API running on heroku with the path: “/employee/id” (where “id” matches the employee’s “_id” property). It will return an Observable of type any, ie: Observable. NOTE: with a “put” request, you can send the data in the second parameter, ie: o return this.http.put(“someURL/”, someData); • getEmployee(id) This method must make a “get” request (using the HTTPClient module) to your Teams API running on heroku with the path: “/employee-raw/id” (where “id” matches the “id” parameter to the function). It will return an Observable of type EmployeeRaw[], ie: Observable<EmployeeRaw[]>. Note, the API will return an array with one element (containing the “raw” Employee object) PositionService (position.service.ts) This service needs to create the following additional 2 methods: • savePosition(position: Position) This method must make a “put” request (using the HTTPClient module) to your Teams API running on heroku with the path: “/position/id” (where “id” matches the position’s “_id” property). It will return an Observable of type any, ie: Observable. NOTE: with a “put” request, you can send the data in the second parameter, ie: o return this.http.put(“someURL/”, someData); • getPosition(id) This method must make a “get” request (using the HTTPClient module) to your Teams API running on heroku with the path: “/position/id” (where “id” matches the “id” parameter to the function). It will return an Observable of type Position[], ie: Observable<Position[]>. Note, the API will return an array with one element (containing the Position object) Step 2 – Creating New Components (EmployeeComponent & PositionComponent) Now that we have our new service methods to fetch a specific employee / position, we can create the components that will enable us to edit existing employees and positions. This involves creating two new components: EmployeeComponent & PositionComponent. Use the @angular/cli (ie: ng generate) to create these components now. Once these components are created, add the following properties / methods according to the specifications outlined below: EmployeeComponent (employee.component.css) To keep the look and feel of our app consistent, we must add the following css: • .center{ margin-top:40px; } EmployeeComponent (employee.component.ts) Properties: • paramSubscription ( type any) • employeeSubscription ( type any) • getPositionsSubcription ( type any ) • saveEmployeeSubscription ( type any) • employee ( type EmployeeRaw ) • positions( type Position[] ) • successMessage ( set to false ) • failMessage (set to false) Methods: • constructor() In this method, we must inject the following Services: o EmployeeService from employee.service o ActivatedRoute from @angular/router o PositionService from position.service • ngOnInit() In this method, we will use Injected services / modules to perform the following tasks: o Determine what the value of the _id variable is in the Route parameter using the ActivatedRoute service (Note: a reference to the subscription should be stored using “paramSubscription” so that it can be disposed of later) o Use the value of _id to populate the “employee” property using the EmployeeService service (Note: a reference to the subscription should be stored using “employeeSubscription” so that it can be disposed of later) o populate the “positions” property using the PositionService service (Note: a reference to the subscription should be stored using “getPositionsSub” so that it can be disposed of later) • onSubmit() In this method, we will use Injected services / modules to perform the following tasks: o Persist (“save”) the “employee” property using the EmployeeService service (Note: a reference to the subscription should be stored using “saveEmployeeSubscription” so that it can be disposed of later) o If the subscription output the data successfully (ie, in the first callback): ▪ Set the value of the successMessage property to true ▪ Using the setTimeout() method, automatically set the successMessage property to false after 2500 ms o If the subscription failed to output the data (ie, in the second callback): ▪ Set the value of the failMessage property to true ▪ Using the setTimeout() method, automatically set the failMessage property to false after 2500 ms • ngOnDestroy In this method we call the “unsubscribe()” methods on any saved subscriptions within the component (ie: paramSubscription, etc) – Note: we must make sure they are not “undefined” before we call “unsubscribe()” PositionComponent (position.component.css) To keep the look and feel of our app consistent, we must add the following css: • .center{ margin-top:40px; } PositionComponent (position.component.ts) Properties: • paramSubscription ( type any) • positionSubscription ( type any) • savePositionSubscription (type any ) • position( type Position ) • successMessage ( set to false ) • failMessage (set to false) Methods: • constructor() In this method, we must inject the following Services: o PositionService from position.service o ActivatedRoute from @angular/router • ngOnInit() In this method, we will use Injected services / modules to perform the following tasks: o Determine what the value of the _id variable is in the Route parameter using the ActivatedRoute service (Note: a reference to the subscription should be stored using “paramSubscription” so that it can be disposed of later) o Use the value of _id to populate the “position” property using the PositionService service (Note: a reference to the subscription should be stored using “positionSubscription” so that it can be disposed of later) • onSubmit() In this method, we will use Injected services / modules to perform the following tasks: o Persist (“save”) the “position” property using the PositionService service (Note: a reference to the subscription should be stored using “savePositionSubscription” so that it can be disposed of later) o If the subscription output the data successfully (ie, in the first callback): ▪ Set the value of the successMessage property to true ▪ Using the setTimeout() method, automatically set the successMessage property to false after 2500 ms o If the subscription failed to output the data (ie, in the second callback): ▪ Set the value of the failMessage property to true ▪ Using the setTimeout() method, automatically set the failMessage property to false after 2500 ms • ngOnDestroy In this method we call the “unsubscribe()” methods on any saved subscriptions within the component (ie: paramSubscription, etc) – Note: we must make sure they are not “undefined” before we call “unsubscribe()” Step 2 – Creating Routes for the Employees / Positions Components Now that we have our new components in place and capable of reading route parameters, we must update app-routing-module.ts and our existing EmployeesComponent & PositionsComponent files so that we can successfully navigate to the new routes for a specific employee / position. app-routing-module.ts Add the following routes: Route Path Component / Options employee/:_id EmployeeComponent position/:_id PositionComponent EmployeesComponent (employees.component.ts) Our goal here is to allow users to click on a specific employee row, which will cause them to be sent to the corresponding employee view (using the /employee/:_id route) To enable this, we must modify the EmployeesComponent according to the following specification • Inject Router from @angular/router in the constructor parameters as “router” • Add the method: routeEmployee(id: string) o In this method, we use the Injected router instance to “navigate” the to the /employee/id route (where id is the parameter passed to the function) – HINT: see this.router.navigate in the “Angular Services Intro” notes EmployeesComponent (employees.component.html) With our new “routeEmployee(id)” method in place, we can now update our EmployeesComponent template (employees.component.html) to invoke the method by binding a “click” event to the sameelement that has our *ngFor directive. This click event will invoke the routeEmployee() method and pass in the value of the current employee’s _id value, ie “routeEmployee(employee._id)” By adding the click binding to the repeatedelement, we can ensure that every singleelement will have the correct event, and invoke the routeEmployee method for the matching employee _id value for that row in the table. PositionsComponent (positions.component.ts) Similar to EmployeesComponent, our goal is to allow users to click on a specific position row, which will cause them to be sent to the corresponding position view (using the /position/:_id route) To enable this, we must modify the PositionsComponent according to the following specification • Inject Router from @angular/router in the constructor parameters as “router” • Add the method: routePosition(id: string) o In this method, we use the Injected router instance to “navigate” the to the /position/id route (where id is the parameter passed to the function) – HINT: see this.router.navigate in the “Angular Services Intro” notes PositionsComponent (employees.component.html) Again, this is the same process as our EmployeesComponent template, ie: we must update our PositionsComponent template (positions.component.html) to invoke the routePosition method by binding a “click” event to the sameelement that has our *ngFor directive. This click event will invoke the routePosition() method and pass in the value of the current positions’s _id value, ie “routePosition(position._id)” Step 3 – Creating the Templates / Forms (EmployeeComponent & PositionComponent) With our Component logic in place, we can now concentrate on creating the templates for our Employee & Position Components. However, before we start, we need to update our assets/main.css file, so that our forms render more clearly in the application: assets/main.css • in the .form-group . form-control style (line 736), change the border-color property from: #f2f2f2 to #d2d2d2 • At the bottom of the file, below all the other styles, add: o .table-hover tr{ cursor: pointer; } With this complete, we can focus on adding our template content / forms to our new Employee & Position Components. IMPORTANT NOTE: Before we can use Forms in Angular, we must: • Import FormsModule from @angular/forms in our app.module.ts • Add FormsModule to the imports: [] array in app.module.ts EmployeeComponent (employee.component.html) To get you started, we have provided some boilerplate, static HTML that can be used to kick start the template: https://scs.senecac.on.ca/~patrick.crawford/shared/winter-2019/web422/A6/employee.component.html.txt Once you have copied the contents of the above .txt file into your employee.component.html file, you should have almost all the fields you will need to update an existing employee: • With this HTML in place, we have a view that features a blank form and placeholder data. We need to update this view to use real data from the component (ie: employee and positions) for all form fields and any other placeholder locations (ie: in the “alert” elements at the bottom and the
…
element at the top). • Regarding the form fields, remember to: o Add (ngSubmit)=”onSubmit()” to your