The goal of this assignment is to help you get acclimated to Angular and TypeScript as a framework, as well as the general structure of and best practices for the CSXL repository. To do this, we will be guiding you through the creation of a simple “To-Do List” component for the CSXL website.
Although the assignment itself is unique to our course, the content will loosely follow Angular’s official “Getting Started” tutorial and draw from the official Angular documentation. Text used from this tutorial/docs will be indicated in blockquotes.
While our TAs are happy to assist as needed in Office Hours, we also highly recommend that you search the documentation links provided first! Being able to parse through and understand docs is an important skill to practice as a software engineer. We also recommend that you seek out documentation for other concepts we don’t explicitly describe/link to. Angular’s documentation is very well-written and quite thorough!
Now, let’s get started!
Set Up
Fully complete the setup instructions found here.
General Exercise Information
Pair Programming Expectations
Both students in the pair should contribute to the assignment equally. Remember, it is critical to your success in the rest of the course that you understand the entire of the assignment, even for the portions you aren’t directly writing code for. The basic functionality and structuring we introduce in this assignment will be the foundation for future assignments and features you create!
To quantify this expectation on our end for grading, each student should have at least 3 commits each (based on the commits we have specified). You may determine who “drives” and who “navigates” for each task. With that being said, the first and last commits are a bit smaller than the others, so you may want to ensure that the same person doesn’t do both of those.
Commit Expectations
We expect you to commit after completing “significant” pieces of functionality. For this assignment, we will explicitly describe when and what you need to commit so you can get a feel for standard commit practice. You may add extra commits if you wish to, but you must have the commits from the write up at minimum.
In the future, we won’t expect specific commits as we will not tell you where to commit, but we will still ensure that good practices are followed.
If you need a refresher on how to commit code, read the basic steps below:
git add [file]
orgit add .
when adding all files to stagegit status
- confirm files in stage and branch are correctgit commit -m "Write commit message here"
- form a commit
GPT/AI Usage Policy
We strongly discourage using ChatGPT or other AI assistants when working on this assignment. While it is okay to use AI for conceptual questions, we recommend that you practice your ability to find and understand documentation on your own - ChatGPT is sometimes inaccurate, and it often doesn’t have knowledge of the design patterns we prefer you to use.
Aside from conceptual help, however, you should not use code sourced from ChatGPT/AI, as this is an Academic Honor Violation. All code written must be your original work.
Step 1: Understanding the Existing To-Do Page Component
Open the frontent/src/app/todo/todo-page/todo-page.component.ts
file. This is a component. (Pro-tip: In VSCode try using fuzzy finding by pressing Command+P on macOS or Control+P on Windows and typing todo-page
to quickly find the file and open it!)
Components are the foundational building blocks for any Angular application. Each component has three parts:
- TypeScript class
- HTML template
- CSS styles
The TypeScript class contains functionality and dependencies for your file. In a very basic way, it’s similar to the Java classes you created in COMP 301, which contained variables and methods to be used for your “features”.
The HTML template contains the structure of the web page, while the CSS styles sheet contains the styling of the page.
Component Decorator
In our file, after the import statements (which allow you to use functionality from other files in the directory), you will notice the following code:
@Component({
selector: 'app-todo-page',
templateUrl: './todo-page.component.html',
styleUrl: './todo-page.component.css'
})
This decorator marks a class as an Angular component and provides configuration metadata that determines how the component should be processed, instantiated, and used at runtime.
The templateUrl
corresponds to the path to the HTML template file. The styleUrl
contains the path(s) to the CSS stylesheets. Remember, if you do not link your HTML/CSS files through this decorator, they will not be attached to the component!
Routing
Inside the component class, you will see the following route defined:
public static Route = {
path: '',
title: 'My To-Dos',
component: TodoPageComponent
};
This route defines how you access the component in the web application. The path
corresponds to the URL that attached to the base routes. The component
corresponds to the component (along with the HTML/CSS attached with it) that you want to display when you navigate to this route. The title
is not a necessary property on a route, but it allows you to give names that can appear in the application when you navigate to a certain component.
On your localhost navigate to the empty To-Do Page (which corresponds to the component you currently have opened) using the button on the side menu. You will notice that the URL is /todo
rather than nothing, as the empty path
in our defined route may suggest. This is because we have a “base” route defined in a separate file! Note that you may need to comment out some of the template code in order for the server to load since there are small pieces that are unimplemented!
If you go to the app-routing.module.ts
file and scroll down a bit, you will see the following code:
{
path: 'todo',
title: 'To-Do',
loadChildren: () => import('./todo/todo.module').then((m) => m.TodoModule)
}
You will see here that this file loads the todo module and each of its children under the path
“todo”. It is necessary that routes are defined in this app-routing
module, but Angular allows you to establish “child” routing modules to better abstract features from one another. More on this in future assignments once we add more components for this To-Do List feature!
Form Control
The final bit of code we would like to explain is the Form Control.
public newItemFormControl: FormControl<string> = new FormControl('');
This Form Control property will be linked to the mat-form-field
in the To-Do Page HTML file.
Tracks the value and validation status of an individual form control.
FormControl
takes a single generic argument, which describes the type of its value.
Constructor
Similar to Java, Angular classes also use a constructor
that is automatically invoked when a new instance of the component is constructed.
constructor(protected todoService: TodoService) {}
The constructor for the To-Do Page doesn’t contain any functionality inside it. Notice todoService
is being declared as a protected instance variable here. It is automatically initialized thanks to TypeScript constructor definition conventions. The actual value assigned to todoService
will be managed by Angular’s dependency injection. This is the preferred way to access service classes and their service methods. Methods can be called from the service using dot notation: this.todoService.method()
.
Step 2: Understanding the To-Do Service
Before you begin writing code, it’s important to understand the other half of Angular components as we write them: Services.
Services contain business logic that may be shared across many components through dependency injection.
To begin, open the the todo.service.ts
file.
Injectable Decorator
Similar to the component, our service contains a decorator as well.
@Injectable({
providedIn: 'root'
})
[This] marks a class as available to be provided and injected as a dependency.
Writable Signal
As indicated in the TODO comment, we would like you to use a WritableSignal
. Please refer back to the documentation if you are unsure how to set this up!
Current Index
We will use the current index as a unique identifier for each to-do list item. This also simulates how databases often manage item entries (more on this in later exercises).
While most databases have an “auto-increment” functionality for numerical indices such that adding an item automatically increases the index, we don’t have that on the frontend. So, be sure to increment this value so it can be used to access items in our list properly!
Note: We cannot use the length of the list as an indicator of the max index, as we may remove items from the to-do list.
Step 4: Model the Data
Before you begin implementing the To-Do list feature, it is important to model the data you will be working with using TypeScript interfaces.
Navigate to the todo.model.ts
file. Complete the TODO in this file to implement the ToDoListItem
interface.
Note: In order to use the ToDoListItem
interface from this external model file, you will need to add the export
keyword before your definition. This will allow you to import it in the files you need.
COMMIT!
Add a commit message with the following text: “Implement ToDoListItem interface”.
Step 5: Implement Functionality to Add To-Do List Items
A good practice when it comes to implementing functionality for a feature is completing each piece “atomically” and testing after you complete each piece, rather than creating each file in isolation. For a feature such as a To-Do list, a natural division is to treat each basic CRUD (create/read/update/delete) as an individual task.
We will start with “create”, or adding to the to-do list!
Service Method
In the todo.service.ts
file, find the method titled addItem
. Read the docstring/TODO comments and complete the method accordingly. Remember, the To-Do item you add to your list should be modeled after the ToDoListItem
.
Note: There is a small typo in the docstring for the addItem
method. The param for the method should be defined as title
representing the name of the To-Do list item, NOT item
!
Component Method
Go to the todo-page.component.ts
file. Follow the TODO comments in the addNewItem
method. Remember, the service method we created takes in the title of the To-Do item as a parameter, so you will need to retrieve that from the form control in order to pass it into service.
Refer back Step 1 if you need a refresher on how the component works.
HTML Template
At the bottom of the todo-page.component.ts
file, you will see a mat-form-field
with the label “New To-Do item” and a button
with the text “Add To-Do”. On that button, as the comment recommends, you must add (click)
event handler to call the method to add a new item to your To-Do list.
Note: There is a typo in the comments of the HTML for the add button! The text inside the button says “delete”, but it should say “add”.
Form Control Property Binding
When implementing the mat-form-field
functionality, you must use “property binding”, as the comment mentions.
Below is a brief description of this concept. For further information, feel free to read the documentation linked here.
Property binding in Angular enables you to set values for properties of HTML elements, Angular components and more.
Use property binding to dynamically set values for properties and attributes. You can do things such as toggle button features, set image paths programmatically, and share values between components.
Click Handling
If you would like more information about how the (click)
event binding works, read the documentation linked here.
Finally, if you have never worked with HTML before, be sure to skim this documentation.
Test Your Code
Now, you can test the new functionality you just added! However, we currently only have one piece of the To-Do list application created, so we aren’t able to see the To-Do list item when its added. So, how do we test?
Similar to other languages’ print
statements, TypeScript has console.log
statements that are useful for debugging and low-level testing. Instead of viewing these in the terminal you view them on the localhost
server. On the server, open the dev tools by right-clicking and inspecting. Click on the “Console” tab. This is where console.log
statements will be printed out!
We recommend adding console.log(this.todoList());
at the end of the addItem
service method to test functionality. After you click your add
button, check to make sure that the todoList is accurate and includes your new item and any other existing items.
If the list seems accurate after some testing, you can now be fairly certain that your add functionality works! Remember that this is low-level, manual testing, though. So, if you find issues testing other functions further down the road, don’t completely disregard the possibility of the source being previous functionality!
COMMIT!
Add a commit message with the following text: “Implement functionality to add to-do list items”.
Further Debugging Suggestions
If something isn’t working as expected, check out the suggestions for “standard” debug statement locations below.
In the addNewItem
method in the component file, you may add console.log
statements in the following places listed below to debug:
- Beginning of the Method:
console.log('addNewItem Method Called);
- This will indicate that the method has been called. If this is logged, you know that your
(click)
handling is working as expected!
- This will indicate that the method has been called. If this is logged, you know that your
- After Retrieving To-Do item Text:
console.log('newItemTitle:', newItemTitle);
- This will log out the value of the
newItemTitle
variable you created. It can be used to confirm that you are retrieving the form control value correctly.
- This will log out the value of the
- After Checking Conditions for Title:
console.log('title condition passed')
- This will confirm that the title is valid and that the service method was called.
- After Calling the Service:
console.log('service method called')
- If this is logged, it confirms that the service method was fully executed.
You can add similar console.log
statements in the addItem
service method to check stages of execution and variable values if necessary.
Step 6: Implement Functionality to Read/View To-Do List Items
Next, you should create a way to view existing To-Do list items. Unlike the add functionality, view does not explicitly require any service methods to be implemented due to our use of signals. Instead, simply go to the HTML file and complete the mat-list
.
@for and @empty Blocks
Inside the mat-list
, we suggest you use @for
and @empty
to loop through the To-Do list to display each item. Check out the documentation linked here if you would like to view examples of how to use these blocks.
Material UI Components
Further, now that you are looking at more of the HTML template, you may notice that there are many elements with the mat
prefix on them. These are Material UI components, which are special pre-built, pre-styled HTML elements that we can use in our HTML.
While some applications manually create each UI element using standard HTML, our repository prefers to always use these existing Material UI components for consistency in styling. We have set up the file such that you do not need to build any HTML as we would like to focus on teaching you functionality. However, in the future using MatUI components will be a graded requirement, so be sure to look into the documentation surrounding them.
COMMIT!
Add a commit message with the following text: “Implement functionality to view to-do list items”.
Step 7: Implement the Functionality to Update and Delete To-Do List Items
Finally, go through each file and follow the TODO comments to add the update and delete functionality. While you don’t necessarily need to follow the exact order we used in Step 5 (you could go HTML -> service and test along the way if desired), you should implement and test each fully before moving on to the next function. Be sure to COMMIT after you finish implementing each.
COMMIT!
For update, add a commit message with the following text: “Implement functionality to update to-do list items”.
For delete, add a commit message with the following text: “Implement functionality to delete to-do list items”.
Step 8: Style the Component
The last step is to style the To-Do page! If you run the localhost right now, you’ll find that the page is functional, but quite poorly organized.
Basic styling to ensure that the page is somewhat user friendly is a requirement. UX is an important aspect of web development that is sometimes forgotten in favor of pure functionality!
For this first assignment, we won’t be too strict about styling - just format the page so it makes sense. However, we highly recommend that you put some effort into styling if you have time, especially if you have little experience with CSS, as it will be considered more heavily in the future.
We recommend running simple Google searches for specific styling needs (CSS can be quite expansive!), but here is some documentation that may be useful as a starting point.
COMMIT!
This commit isn’t necessary if you decided to do your basic styling after you finished each part of the HTML template.
Otherwise, add the following commit message: “Style to-do list component”.
Step 9: View Your Work!
Congratulations!! You just created your first Angular feature in the CSXL repository! Play around with the feature and admire your work. :D
While you should have also been testing each method/button sa you created them, this is also a good opportunity to check for any bugs. It’s always a good idea to manually test your feature once you complete it to ensure everything works.
Submission
Once your code is fully tested, push your code up to your Github repository using git push
. Then, go to Gradescope and complete the exercise submission there!
Note: Be sure to record your demo video before you close out your container to avoid having to reinstall again! :)