> ## Content Index
> Fetch the complete content index at: https://www.bentumbleson.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Compounding 101 - learning JavaScript along the way
- URL: https://www.bentumbleson.com/savings-calulator-v1/
- Published: 2018-09-30T00:13:11.000Z
- Updated: 2022-10-24T04:35:21.000Z
- Description: Compounding is such a magical concept in numbers and particularly finance. As I step further in building skillsets in web design, I'll build a reactive compounding calculator with a visualization using Vue.
- Author: Benjamin Tumbleson
- Tags: #Import 2024-08-30 21:32

![](https://www.bentumbleson.com/content/images/2018/09/undraw_Calculator_0evy.png)

As a continuation to my last post, [*Approaching the Problem*](https://www.bentumbleson.com/approaching-the-problem/), I had time recently to sit down and put "pen to paper" so to speak. As a learning initiative, I set out to build a simple savings calculator from start to finish. I'm pleased to report that I've got something up and running. Much credit to the many StackOverflow threads, Mozilla Developer docs, and some of my more qualified programmer friends for the help. Feel free to play around with it in its current state. Note that there isn't a single line of CSS (although the chart is mildly styled). You can view the full source from JSFiddle. 

I did have a few challenges along the way. Unfortunately I didn't document them in the moment, but here's a short list of them.

**1) Converting an object to single set of values**

In order to handle the calculation for each data point, there's a computed section within my Vue instance that runs a `for` loop, calculating the relevant totals and ages at each time frame. In my case, I'm storing two different `key: value` pairs, `total` and `age`. Since this is an object, I can't inherently just immediately pass that object to ChartJS and expect to be able to read it. Additionally, I need to be able to separate out the values as `total` becomes the y-axis data, and `age` becomes the labels (x-axis).

It look me awhile to figure this out, and again, credit to everyone else that ever had this problem and documented it, as I was able to use `object.values` with `map` to return only one set of the values from the pair.

In case you're curious, this is what that bit of code looks like:  
`Object.values(demo.timeData).map(function (a) {return a.total});`

A few quick notes on there:

1. `Object.values` is a Javascript function that converts my object into an array, which can then be used with `.map` which can iterate though the array, returning only those values for which the key was `total`.
2. `demo.timeData` refers to the actual data that VueJS is calculating, as `demo` is the element (or `el` in Vue), and `timeData` is the computed object.
3. `function (a) {return a.total}` is the ES5 (thus IE supported) syntax of defining such a simple function to only return the `total` value. In ES6 supported browers (IE8+ and everything else), this could have been written as `(a => a.total)`

---

**2) Finding data in the DOM**

Sometimes I had cases where I thought I was updating the correct value, and I'd have a console.log setup to spit it out, yet when it ran, it didn't actually update the correct values. The underlying issue here is that I wasn't properly using Chart.js's options for updating chart data. 

In my limited understanding, I thought that if I directly updated data variable I was using in Chart.js, then called chart.update();

In my limited understanding, I thought that if I directly updated data variable I was using in Chart.js, then called `chart.update();`, it would pickup the new data and labels I was passing along as Vue recalculated the information. Unfortunately that wasn't the case, and produced this odd scenario wherein I could use the console to read `totalresult` (which was my variable for the data itself), and it'd return the original values that are calculated when the page loaded originally, but if I used `console.log` to dump `totalresult` when then `onChange` event was triggered, it would dump the *updated* calculation of the numbers.

For reasons I never truly understand, it's as though the `totalresult` existed in two places, likely one inside my Vue instance, and one outside. As such, it gave the impression that my data wasn't updating as expected.

Turns out, to update the data that the chart was pulling, I needed to directly update the dataset (and labels) that `myChart` had stored:  
  
```
  myChart.data.datasets[0].data = Object.values(demo.timeData).map(function(a) {
    return a.total
  });
  myChart.data.labels = Object.values(demo.timeData).map(function(a) {
    return a.age
  });

```

You can even see above the `Object.values` and `map` function that I explained in my previous point.

---

**3) Ternary vs if, else statement**

![](https://www.bentumbleson.com/content/images/2018/09/Screen-Shot-2018-09-01-at-7.39.39-PM.png)

Here's a screenshot of some of my original code that was used to calculate the actual data from the chart. At first glance, it made sense to me: if `$i` (an incrementing number) was 0, then `total` is equal to whatever you started with, `this.initialCapital`. However, once `$i` \> 0, then you'd need to do a calculation of the total.

However, this didn't work. Console told me there was an `Unexpected token if`.

After syncing with a friend of mine, he told me that I couldn't use a conditional like this, and I'd need to use a [ternary](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional%5FOperator?ref=bentumbleson.com). While I was unable to find clear documentation as to *why* the conditional wouldn't work, changing the expression to a tenery fixed the problem.

I'll also mention that what you're seeing above, even changing with a ternary, doesn't fully solve the problem. Only the first value of the set returns correctly. The flaw in this approach is `this.total` inside the `total` calculation. Based on my understanding, I was trying to access the object with the data as `this`, but you can't do that. Instead, I'd need to pull the value out of the loop so that it can keep its value and increase throughout the loop.

---

**4) *data\[i\]* vs *data\[i - 1\]***

Although I ended up going a different direction, based on the above, wherein I pulled the total out of the loop altogether, I did explore my original approach, which wrongly used `this.total` inside the loop.

If I had wanted to truly use `total` inside the loop, I'd need to access it as a subset of `data`. So instead of writing `this.total`, I wrote `data[i].total`.

(if you have a keen eye, you can see I dropped the "$" from my `i` variable)

Turns out that `data[i].total` still doesn't work:

```
Error in render: "TypeError: Cannot read property 'total' of undefined"

```

It doesn't work because I'm still in the process of defining that index. So as the code looped and did `data[2]`, because it hasn't been defined, trying to access the `.total` of an undefined index, is undefinied. Using `data[i-1]` solves this problem. So for example, when `years_to_go == 2`, you want to base the `total` off of `years_to_go == 1`. As such, you need the `-1` in the data, or else you're trying to access a value (the total), that does not yet exist in the loop.

---

As a small side note, I ended up not using vue-chartjs, the Chart.js wrapper for Vue.js. Although I found a lot of references in much of the material I found, it was pretty clear to me that using it would be a bit overkill, especially for a single chart. For implementations that utilize multiple charts, with varying sets of data and styling, this wrapper would tremendously lift that burden. In my case, it was unnecessary. 

---

To wrap up this project, I'll move forward with making the calculations a little more complex, and adding some styling so it can be a standalone page, rather than just a bare set of inputs.