Angular Course Lessons
Angular Project
Recently, I've been learning the latest version of Angular (v18 at the time of this writing) using a course on Udemy called Angular - The Complete Guide (2024 Edition) by Maximilian Schwarzmuller. The course is great and I've gotten up to the first project in the course where we build a financial calculator in Angular. I was happy that I was able to successfully build a project on my own before watching Max's tutorial on the build. However, I knew even when writing the code that it had some issues. I had learned quite a lot from Max's tutorial and I wanted to discuss the issues and things I learned in this blog post.
Don't resist the AppComponent
One of the first things that I learned from Max's walkthrough is that its OK to use the AppComponent as a top level parent component. For whatever reason, when I was developing this project I kept resisting using the AppComponent. Partially because I was trying to integrate a service into the project at the same time as using the Parent-Child component pattern in the project. In this project it made most sense to just pick one pattern or the other.
This is how I initially designed the Parent-Child relationship in my components in this diagram, completely ignoring the AppComponent at the top of the tree.
But this was how Max's solution was structured and it makes much more sense using the AppComponent in the relationship tree.
I had began with a structure like Max's, however I could not figure out how to emit events to my other component without using the AppComponent. For whatever reason my mind, could not see that as the common parent I needed to use. In the end the design I created worked, its just not an optimal structure.
Javascript Coercion
Within the starter project files a javascript file was provided that has a function to perform the investment calculations. Part of your task was to adapt that file to your Angular project. During my build of the project, I kept running into issues with calculations because javascript was coercing variables in the function into strings even though I set the variables as number types in my Angular file. I eventually fixed my issues by typecasting the variables in the calculation function, however, I knew there was something wrong nonetheless.
Here I had wrapped multiple variables in the for loop in Number()
casting because they always were being concatenated as strings otherwise. But this didn't make sense because I had declared them as number. Something was wrong with this.
public initialInvestment!: number;
public annualInvestment!: number;
public expectedReturn!: number;
public duration!: number;
...
for (let i = 0; i < this.duration; i++) {
const year = i + 1;
const interestEarnedInYear = Number(investmentValue * (this.expectedReturn / 100));
investmentValue = Number(investmentValue) + Number(interestEarnedInYear) + Number(this.annualInvestment);
const totalInterest =
Number(investmentValue - this.annualInvestment * year - this.initialInvestment);
The true issue that I learned from Max's walkthrough is actually pretty simple. When passing data in Angular through the HTML templates, that data is always passed as strings regardless of how you typed the variables. So all those variables that I "assumed" would be numbers because you know, I typed them as such, were actually strings. And that caused my issue. Funny thing is Typescript never scoffed once at the fact the number types I set on the variables did not match the string values they were receiving. Oh well...
Services are independent
As I mentioned with my Parent-Child design issues before, I had begun using a Service in conjunction with Input/Output operators in the Components. Well, I kind of flubbed here. I could have simply used the Service alone and completely ditched Input/Output decorators and freed my components from the Parent Child relationship dependencies. While some of the data I was storing in the service was setup correctly, I was still passing that data between Components using the Input/Output decorators and Event Emitters. I realize this was silly.
I could have simply modified my code to call the function from the service, pass in the input, and then have my other component fetch the output data directly from the service. Instead I computed the data in the service, copied the data from the return value, placed that into an Event Emitter, passed the data to my other component, and then inputted the data into the fields where it belonged. My way was definitely less efficient, though it worked and Angular is still rather performant so I didn't notice any issues. It was definitely not easy to follow though.
Wrap up
So with this project I learned three important lessons.
-
There is nothing wrong with using the AppComponent in the component hierarchy if your using a Parent/Child pattern in your project. Furthermore, be aware of how your Parent/Child relationship is mapped. Ask yourself, "does it make sense"?
-
If you run into issues with coercion that require you resort to casting multiple values to a certain type, look further upstream in your code to make sure that your not missing something important. And double-check your understanding about how your frameworks "work". Its always when we make an assumption about how something is "supposed to" work that we end up in trouble.
-
Services used correctly can really help you free your components from having to be laid out in specific hierarchies. It can also help you when there is no common hierarchy for your components. Consider that the service is an interface to the data and methods that you store in it. Your components are meant to use it directly from the service. Don't copy data out of the service, just use it directly.