Fantastic FinTech —An Awesome Opportunity Cost App with Angular

Victor Barbarosh
Practical Coder’s Chronicles
9 min readOct 14, 2023

Our everyday life in general, and our personal finance, is full of decision-making moments involving tradeoffs. One important concept related to these tradeoff decisions is the opportunity cost.

Generated by DALL-E, on my personal, clear, and very creative instructions!

What do I offer you in this post?

  1. Brief description of what Opportunity Cost is and how can it help you decide whether you need to spend your buck on something, and why or why not.
  2. Walk you through the main steps of implementing an Angular App that would do just this — show you how much of one thing will cost you in terms of a really important other thing, if you decide to buy it.

1. Opportunity Cost in a Nutshell

Put it simply, when facing two options that would require from you the same resource to give up, you’ll need to evaluate the Opportunity Cost of each before choosing between tem.

Example — you have $20.00 in your pocket and your teammates ask if you want to go for lunch at some place, outside the office. You have your own lunch but you think it can be put in the fridge and kept for the next day.

You also, have to be home this evening (assuming you still commute and go work in an actual office, from time to time, you lucky hybrid employee) by 16:00. Your commute will cost you $4.00.

So what would you do? You have $20.00 that may serve you two different purposes but you need to choose whether you give them all in one shot on the lunch or you can spare them for commute time. In fact, you spare them for 5 commutes in the near future, since $20.00 / $4.00 will let you take the bus 5 different times

Of course, there is more to these choises, if you look at them from many angles. You may weigh in what’s more important, socializing with your teammates an hour or making your family happy by being on time, catching up with the latest gossips in the office or getting earlier back home and finishiing that article you want to write on Medium, etc.

This comparison of how much of Option B you give up by taking Option A is just the most natural, stright forward way of getting a real sense of what one option would cost you in terms of another.

With no further ado, let’s implement one, quickly.

2. Implementing the Opportunity Cost Angular App

Step 1 — Generate you boilerplate Angular App

Hope you already have experience with Angular but if not I bet you can find some good “get started with…” resources. If you don’t like those leave me a comment below with what you would like to see in the next article and I’ll prepare it for you.

Back to the plan. Here are the Angular, node and npm version I am using for this example:

$ node --version
v18.14.0

$ npm --version
9.8.0

$ ng version

_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/


Angular CLI: 15.2.2
Node: 18.14.0
Package Manager: npm 9.8.0
OS: darwin x64

Angular:
...

Package Version
------------------------------------------------------
@angular-devkit/architect 0.1502.2
@angular-devkit/core 15.2.2
@angular-devkit/schematics 15.2.2
@schematics/angular 15.2.2

Now, in order to create your first Angular app, go to the location in your file system where you want generate it and run the following command:

ng new opportunity-cost
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? CSS

As you can see, we don’t add routing and we chose simple CSS for the sake of this example.

Now, feel free to cd inside your new angular project and run ng serve You app should compile and be served in the browser.

$ cd opportunity-cost
$ ng serve

# Expected Output below:
✔ Browser application bundle generation complete.

Initial Chunk Files | Names | Raw Size
vendor.js | vendor | 1.71 MB |
polyfills.js | polyfills | 314.84 kB |
styles.css, styles.js | styles | 209.96 kB |
main.js | main | 46.63 kB |
runtime.js | runtime | 6.53 kB |

| Initial Total | 2.28 MB

Build at: 2023-10-12T00:31:57.680Z - Hash: c0d3d63fafe10e62 - Time: 10203ms

** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **


✔ Compiled successfully.

Step 2 — Add the main logic of the Opportunity-Cost

In order to have a better structure we’ll put the Opportunity-Cost logic in a separate Component.

We create a new component inside our Angular App by running ng g c opportunity-cost-calculator which is short from angular-cli (aka ng) please generate (aka g) a new component (aka c) named opportunity-cost-calculator, which angular-cli did for us.

$ cd opportunity-cost
$ ng g c opportunity-cost-calculator
CREATE src/app/opportunity-cost-calculator/opportunity-cost-calculator.component.css (0 bytes)
CREATE src/app/opportunity-cost-calculator/opportunity-cost-calculator.component.html (42 bytes)
CREATE src/app/opportunity-cost-calculator/opportunity-cost-calculator.component.spec.ts (734 bytes)
CREATE src/app/opportunity-cost-calculator/opportunity-cost-calculator.component.ts (284 bytes)
UPDATE src/app/app.module.ts (476 bytes)

You’ve got some generic code automatically created under src/app as indicated in the output terminal.

Your file structure inside your shiny new Angular app should look like this now (use the tree <dir-name> command to get this nice view).

$ tree src/ 
src
├── app
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ ├── app.module.ts
│ └── opportunity-cost-calculator
│ ├── opportunity-cost-calculator.component.css
│ ├── opportunity-cost-calculator.component.html
│ ├── opportunity-cost-calculator.component.spec.ts
│ └── opportunity-cost-calculator.component.ts
├── assets
├── favicon.ico
├── index.html
├── main.ts
└── styles.css

Let’s add some logic to the component file because what’s the point to add colors and views if there is nothing behind it that would do an actual useful thing.

In the opportunity-cost-calculator.component.ts file we’ll add the following functions and attributes:

// we'll need a form thus we need certain FormGroup and FormControl objects  
myForm: FormGroup;
referenceValue: FormControl;
referenceName: FormControl | undefined;
newItemValue: FormControl | undefined;
newItemName: FormControl | undefined;
conclusionIsReady: boolean = false;

// the constructor will clear the form at every refresh
constructor(private fb: FormBuilder) {
this.myForm = fb.group({
'referenceValue': [null, Validators.nullValidator],
'referenceName': ['', Validators.nullValidator],
'newItemValue': [null, Validators.nullValidator],
'newItemName': ['',Validators.nullValidator ],
});
this.referenceValue = this.myForm.controls['referenceValue'] as FormControl;
}

// on init page, we'll start listening to those fields of interest
ngOnInit() {
// @ts-ignore
this.referenceValue.valueChanges.subscribe(value => {
// Make sure the control exists before using it
this.referenceName = value.referenceName;
this.referenceValue = value.referenceValue;
this.newItemName = value.newItemName;
this.newItemValue = value.newItemValue;
});
}

//usual submit function
onSubmit(form: any): void {
this.referenceName = form.referenceName.value;
this.referenceValue = form.referenceValue.value;
this.newItemName = form.newItemName.value;
this.newItemValue = form.newItemValue.value;
}

// reset it when needed, we shouldn't force the user to refresh the page, right
resetForm() {
this.myForm.reset();
}

// this is a very simple math operation that gives you the quantity of new item
// you want to buy, in terms of the price of your reference item
calculateQuantity(): String {
const referenceValue = this.myForm.value.referenceValue;
const newItemValue = this.myForm.value.newItemValue;
let finalWorthItMessage = 'By choosing differently, you could afford ';
if (referenceValue >= newItemValue && referenceValue > 0 && newItemValue > 0) {
finalWorthItMessage += this.formatDecimal(referenceValue / newItemValue);
} else if (referenceValue < newItemValue && referenceValue > 0 && newItemValue > 0) {
finalWorthItMessage += this.formatDecimal(newItemValue / referenceValue);
}
finalWorthItMessage += ' ' + this.myForm.value.referenceName + '(s) instead of just one ' + this.myForm.value.newItemName;
finalWorthItMessage += ' illustrating the substantial opportunity cost you gain.';
return finalWorthItMessage;
}

// a simple custom validation function that allows us to control when the
// result of our calculation is displayed
areFormControlsValid(): boolean {
const formControls = this.myForm.controls;
if (formControls['referenceName'].value !== null &&
formControls['referenceValue'].value !== null &&
formControls['newItemName'].value !== null &&
formControls['newItemValue'].value !== null) {
return (
formControls['referenceName'].value !== null &&
formControls['referenceValue'].value !== null &&
formControls['newItemName'].value !== null &&
formControls['newItemValue'].value !== null
);
}
return false;
}

// some divitions result in really weird floating numbers so we correct this
formatDecimal(decimalNumber: number): string {
// Use the toFixed method to format the number to two decimal places
return decimalNumber.toFixed(2);
}

Step 3— Add the form for the Opportunity-Cost

Now that we have the logic in place, we can put the form in our template file.

In the opportunity-cost-calculator.component.html file we’ll need the following elements:

<div class="ui raised segment">
<h2 class="ui header">
<div class="inline-image-container">
<img class="inline-image" src="assets/images/worthit-32x32.png">
Trade-Off Assessment Tool
<img class="inline-image" src="assets/images/worthit-32x32.png">
</div>
</h2>
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm.value)" class="ui form" [class.error]="!myForm.valid && myForm.touched">
<div *ngIf="areFormControlsValid()" class="ui message">
{{ calculateQuantity() }}
</div>
<div *ngIf="!areFormControlsValid()" class="ui message">
Waiting for your input, below...
</div>

<h4>Step 1 - Fill in your Golden Standard (reference) Info</h4>
<div class="field">
<label for="referenceNameInput">Golden Essential Name</label><br>
<input type="text" id="referenceNameInput" placeholder="e.g., Weekly Groceries" formControlName="referenceName">
</div>

<div class="field">
<label for="referenceValueInput">Golden Essential Cost ($)</label><br>
<input type="number" id="referenceValueInput" placeholder="e.g., $200" formControlName="referenceValue">
</div>

<h4>Step 2 - Fill in the New Item Info that you are about to buy</h4>
<div class="field">
<label for="newItemNameInput">New Item Name</label><br>
<input type="text" id="newItemNameInput" placeholder="" formControlName="newItemName">
</div>

<div class="field">
<label for="newItemValueInput">New Item Cost ($)</label><br>
<input type="number" id="newItemValueInput" placeholder="" formControlName="newItemValue">
</div>

<br>
<button (click)="resetForm()"
class="ui button button-reset"
title="Reset the form">
<i class="fas fa-sync"></i>
</button>
</form>

</div>

Step 4— Make it look nice

Having the bare logic and the html code doesn’t make it too appealing to use it, if honestly.

Thus, we’ll format the apprearance a bit so that we have a certain degree of enjoyment when playing around with our app, as well.

In the opportunity-cost-calculator.component.css file we add some refinements:

.ui.raised.segment {
padding: 20px;
background-color: #f7f7f7;
border: 2px solid #d3d3d3;
border-radius: 3px;
}

.ui.header {
max-width: 45rem;
margin: 2px auto 10px;
color: #333;
text-align: center;
}

.ui.form {
max-width: 45rem;
margin: 2px auto;
}

.ui.button {
margin: auto;
text-align: center;
display: flex;
background-color: greenyellow;
color: blueviolet;
font-size: 20px;
border: none;
border-radius: 50px;
padding: 20px;
cursor: pointer;
}

.ui.button:hover {
background-color: #0056b3;
}

.ui.message {
margin: auto;
text-align: center;
display: flex;
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
border-radius: 5px;
padding: 20px;
}

/* Align input fields to the right */
.field input {
text-align: left;
}

div .inline-image {
height: 25px;
width: 25px;
}

Step 5— Give it a try!!!

Run your app, and you’ll be able to see something similar to this in your browser, when navigating to http://localhost:4200/ Great job!

The Opportunity Cost Calculator App you just built!

Let’s try it a bit.

My weekly grocery is about $400.00 right now, as of Sepetmber 2023 (yes, the inflation is a big pain nowadays) so how does it compares with a new Toyota Camry I would like to buy for $40,000.00 ?

It seems it will take me 100 weeks of food, which is roughly two years of starving…, so do I want it now that I know the relative cost of this luxury? Definitely not!

See a full demo here:

Conclusions

In this post, you went through the concept of Opportunity Cost and read a few examples.

You have implemented a brand new Angular App that would help you take the right decision for your money.

It’s unbelievable simple and incredible powerful tool you just got. Next time you see a new Playstation or a shiny iPhone with a tag price of $500.00 or $1,000.00 respectively you won’t be wondering whether the price is good for you or not. Once you have a reference price to compare with all the time (i.e. grocery bills for a week, in my case) you’ll definitely take a better decision!

Bonus content

If you want a different take on what GitHub is check my other post here where I describe GitHub main concepts/features by comparing them with some essential financial operations.

For complete source-code for the Opportunity-Cost Angular App discussed here, go to the GitHub repository, embedded below.

If you don’t know what a GitHub repository is, or even if you know but want to see a new take at what GitHub is in general, check my other post here where I describe GitHub main concepts/features by comparing them with some essential financial operations.

Thanks for reading, and see you soon with some fun real-life applications of software!

Call for Action

As a reader, your participation matters. If my words strike a chord, I’d appreciate your applause (aka Clap), a follow, and your valuable comment. Let’s engage in this realm of ideas and make our mark, one interaction at a time.

--

--

Victor Barbarosh
Practical Coder’s Chronicles

I am a full-stack software dev, writing about code, money & code of money, in all their forms and beauty!👉🚀