Step 8: Budgeting
This is part 8 of an 18 part series titled Vue.js Application Tutorial - Creating a Simple Budgeting App with Vue. It is highly recommended that you read the series in order, as each section builds on the last.
- Step 0: Intro
- Step 1: Planning Your Application
- Step 2: Data Architecture
- Step 3: Setup & Project Structure
- Step 4: Create & View Accounts
- Step 5: Edit & Delete Accounts
- Step 6: Adding LocalStorage to our Vue.js Application
- Step 7: Interlude & Refactor
- Step 8: Budgeting
- Step 9: Racing Through Budgets
- Step 10: Styling & Navigation
- Step 11: Finishing Budgets with Vue.js Dynamic Components
- Step 12: Planning for Transactions
- Step 13 - All Aboard the Transaction Train
- Step 14 - User Testing
The next entry is expected to be published on 03 August 2017. Sign up using the form at the bottom of this post to receive updates when posts are published.
Before we dive into our Budgets module let's recap both where we are in our code and how our application will function with regards to budgets.
The road so far
I like to look at things from a user's perspective. At this point they can
- load the application and see the accounts page by default
- click to add an account with a balance, category, and name
- view the list of all accounts they have added
- edit an account's name and category (but not its balance)
- delete an account
- return to the application later and see the data they entered
It might feel like it took a long time to get to where we are. Because we setup a solid foundation most of the rest of the application will practically build itself. Here are some of the less user facing programming tasks we've accomplished.
- we setup a module based project structure with a mind on growing to a mid to large size application
- we are using vuex and vue-router
- our data is being stored with with the ability to perform ID based lookups
- our store can be used to communicate between all of our components and ensure data consistency
- all of the data is stored in local storage
- the API is a discrete component, making it easy to swap out if we wanted to
Budgeting for budgets
Let's not skip out on planning the next module simply because we're on fire from finishing Accounts
! We want to think through the workflow for budgeting, and maybe even sketch out some screens.
Each month a user will budget their hard earned money toward various categories. They might budget $140 toward their utility bill, $300 toward groceries, $1000 toward rent, $10 to Netflix, and so on. The budget can change from month to month, but we want to give them an easy way to simply copy last month's budget over. We also need to track how much they actually spend toward each budget category. Spending will take place in transactions, where each transaction will be assigned to a budget category, but we want to track the total on the budget object for easy lookup.
We won't worry about any reporting or analysis yet - that should be its own module.
Take the time now to think through the data object on your own so you can compare it to what I come up with.
My biggest question with storing this information is whether the categories should be distinct objects or simply names in the budget object. This goes right back to our relational question from earlier. If categories are their own type, it's easier to get a list of categories without having to aggregate all of the budget objects. But it adds an extra lookup every time we want to query by category.
Here is the simplest way to store budgeting data for a single category and a single month:
'jcijeojde88': {
'id': 'jcijeojde88',
'name': 'Groceries'
'budgeted': 150,
'spent': 87.36,
'date': '2017-02-16T22:48:39.330Z'
}
This is what it would look like if we used category objects:
'budgets': {
'jcijeojde88': {
'id': 'jcijeojde88',
'category': 'ijdoiejf8e',
'budgeted': 150,
'spent': 87.36,
'date': '2017-02-16T22:48:39.330Z'
}
}
'categories': {
'ijdoiejf8e': {
'id': 'ijdoiejf8e',
'name': 'Groceries'
}
}
You might have also considered storing each month as an object containing multiple budgets:
'budgets': {
'de7ednve': {
'id': 'de7ednve',
'date': '2017-02-16T22:48:39.330Z',
'budgeted': 1359.29,
'spent': 1274,
'income': 1459.41,
'budgetCategories': {
'jcijeojde88': {
'id': 'jcijeojde88',
'category': 'ijdoiejf8e',
'budgeted': 150,
'spent': 87.36
}
}
}
}
'categories': {
'ijdoiejf8e': {
"id": "ijdoiejf8e",
"name": "Groceries"
}
}
This makes looking at monthly data easier since we once again don't have to aggregate it. And we also keep a running total for monthly values. While this method adds some complication to our data storage and retrieval, most of the time when a user is viewing their budget it will be in a monthly view. This monthly setup makes the most sense to me despite some of its drawbacks.
Here are some of the actions the user will be performing:
- view their budget for this month
- add a spending category with a budgeted amount
- check how much money they have left to spend in a category
- update the amount of money budgeted toward a category
- copy their entire budget from last month
- view how much they budgeted and spent in each category for previous months
- check their total income, budget, and amount spent for this month
Just like before, take a minute and think through what the first steps should be to build out this section of the application.
Here is my list.
- add a budget "month"
- add individual budget categories to the created month
- as budgets are added update the month record
- automatically generate IDs for the month and the budgets
- create the "month" view component so the user can see their budget for that month
- save and load data from IndexedDB
- add a route for each component
- navigate between accounts and budgeting
The Budgets is already more complicated than Accounts, but it isn't too bad. There is no communication yet between our modules - the upcoming Transactions is really the glue between Budgets and Accounts.
We will need to drop back soon to think through our application's navigation and styling, as right now they are functional placeholders.
There was no code in this section, but the next one we'll begin to race through the Budget module we just planned. Stay tuned.