ga-wdi-exercises/project4

mean app - failure to load resource for certain views

Closed this issue · 12 comments

https://github.com/twelve13/budgeting

for my budgeting app, a user has many accounts, and each account has many withdrawals and deposits.

I'd like there to be three "views"

  1. the welcome page shows all the users with links to each user's dashboard
  2. the dashboard page shows the user's accounts with links to each account
  3. the account page shows all the account's withdrawals and deposits

on the master branch, when i go to http://localhost:4000/#/users/Caroline, it does show the correct account information for user Caroline

however I'm having trouble getting the users to show on the welcome page, and getting the withdrawals and deposits to show for an account. see showroutes branch.

http://localhost:4000/#/welcome
gives GET http://localhost:4000/users 404 (Not Found)

(typing in the id of the account into the url)
http://localhost:4000/#/users/Caroline/accounts/5932e4ec34346fea23ed9e97
gives GET http://localhost:4000/accounts/5932e4ec34346fea23ed9e97 404 (Not Found)

I'm missing some link....
thanks!

It looks like your showroutes branch is the most up to date, so I'll be referencing that.

The /users/:name api route is set to only respond to urls with an explicit name provided. This means /users/Caroline, but not /users. To make the named param optional we add a ? to the end of the variable: /users/:name?

Once you do that, you'll then need an if statement to switch between using models.User.findOne() or models.User.find() depending on if req.params.name is set or undefined.

The accounts route is a little more complicated. First there's a mismatch between what the api route expects /users/:name/accounts/:id (a name and account id) and your angular account resource factory accounts/:id (missing the users/:name part).

Once you add the user name part to your angular resource, the api method needs to be updated. You have a Account model search via findOne but this will fail because your Account objects are nested documents beneath the User and not their own collection. You'll need to perform a User search first, and then use an array iterator to find the correct account from user.accounts

Let me know if you have any questions or need more clarification.

thanks for the detailed feedback! I worked through all but the last part. here's my attempt right now:

//perform a user search first, then use an array iterator to find the correct account from user.accounts

app.get("/users/:name/accounts/:id", (req, res) => {
	var user = models.User.findOne(req.params);
 	user.accounts.forEach(function(account){models.Account.findOne(req.params).then(function(account) {
 		res.json(acount);
 		});
 	});
 });

There's a couple of things we need to fix here.

First that User.findOne won't return a user instance to that assignment, it will only be available inside of a callback or promise function.

It will be inside that function where you can iterate over the user.accounts array with forEach or use another array enum to match an account object to the url supplied id and send it back.

Again models.Account.findOne won't retrieve an account record for you because they don't exist in their own top-level collection. Based on your seed data Accounts are nested inside of individual User documents.

Thank you! re: match an account object to the url supplied id and send it back
can I write an if statement to see if it matches?
is the url supplied id captured by just req.params?

here's where I am now:
https://github.com/twelve13/budgeting/blob/showroutes/index.js#L32-L44

Hi Caroline, looking at that piece of code, I notice a few problems:

  1. for the User.findOne() method, you need to give it an object that will specify you are querying on the user's name property and supply req.params.name
  2. To match the account, your current logic will work but you need to query on req.params.id
  3. A more DRY way to write the matching logic is using javascript's .find() higher-order function
app.get("/users/:name/accounts/:id", (req, res) => {
	models.User.findOne({ name: req.params.name }).then(function(user) {
 		user.accounts.find(function(account){
                     account._id === req.params.id
                     // This assumes that your accounts have id properties that you are passing into
                     // the url on the ui-sref directive
 		});
	});
 });

https://github.com/twelve13/budgeting/blob/showroutes/index.js#L32-L39

thank you! i tried that and it still gives me this error:

angular.js:11630 GET http://localhost:4000/users/accounts/5932e4ec34346fea23ed9e97 404 (Not Found)

I noticed that the error is regarding /users/accounts/id and not . users/name/accounts/id

do i need to alter my angular code too?
https://github.com/twelve13/budgeting/blob/showroutes/public/js/app.js#L66-L82

Oh wait, sorry, you need to tell it to send back the json in your express method:

app.get("/users/:name/accounts/:id", (req, res) => {
	models.User.findOne({ name: req.params.name }).then(function(user) {
 		let account = user.accounts.find(function(account){
                     account._id === req.params.id
 		})
 		res.json(account)
	});
 });

And yes, in your Angular code, you need to query the AccountsFactory by giving it both a name: for the user and an id: for the account:

function showControllerFunction ($state, $stateParams, AccountFactory) {
	 	this.account = AccountFactory.get({name: $stateParams.name, id: $stateParams.id});
	 }

Which, in turn, means that there needs to be a name property in the parameters to retrieve that would be set by the ui-sref link that activates a transition to that state.

function FrameworkShowControllerFunction($state, $stateParams, frameworkFactory){ this.framework = frameworkFactory.get({end: $stateParams.end, title: $stateParams.title}) }

Backend:
app.get("/api/ends/:type/frameworks/:title", (req, res) => {
End.findOne({type: req.params.type}).then(function(end){
let framework = end.frameworks.find(function(framework){
framework.title === req.params.title
})
res.json(framework)
})
})

great - the error message finally went away!

however, when I click on the link to go to the account page, I get
angular.js:11630 GET http://localhost:4000/users/Caroline/accounts 404 (Not Found)
(there is no id number after users/Caroline/accounts

if i manually type in the account id at the end, I get no error, but the interpolated js still doesn't show

i tried doing a console.log(this.account.name) in the ShowControllerFunction, and it's coming back as undefined

https://github.com/twelve13/budgeting/blob/showroutes/public/js/app.js#L80-L83
https://github.com/twelve13/budgeting/blob/showroutes/public/js/ng-views/dashboard.html#L7
https://github.com/twelve13/budgeting/blob/showroutes/public/js/ng-views/show.html#L3