Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Express Basics Parameters, Query Strings, and Modularizing Routes Randomize Cards

Brian Patterson
Brian Patterson
19,588 Points

Getting a 404 when I click the answer link.

I have tried to follow along and this is the code I have written.

const express = require('express');
const router = express.Router();
const { data } = require('../data/flashcardData.json');
//the above is the same as:
//const  data  = require('../data/flashcardData.json').data;
const { cards } = data;

router.get('/:id', (req, res) => {
  // Here, we're setting either the string "answer" or the string "question" to a variable called side
  const side = req.query.side; // "answer"
  // Here, we're setting the index of the client's desired "card" to a variable called id
  const id = req.params.id; // 1232
  // This step has two parts: we're getting the specific "card" from the "cards" array using the id variable as an index number
  // Then, once we have a "card" object, we're grabbing the string of text inside of its "answer" property and assigning it to the variable "text"
  // We get the string of text inside of "answer" — instead of "question" — because that's what the value of "side" above happens to be
  const text = cards[id][side];
  // Similarily, "hint" will contain the the string of text inside of the "hint" property of the the selected "card" object
  const hint = cards[id];
  // This step is really for readability and is arguably unnecessary
  // Basically, you're setting "templateData" with {text: "Something, something, answer", hint: "hint for the question"}
  const templateData = { id, text };
  // Finally, we build our card.pug template using the contents of templateData, and send the resulting HTML to the client

  //get answer from question.

  if (side === 'question') {
    templateData.hint = hint;
    templateData.sideToShow = 'answer';
    templateData.sideToShowDisplay = 'Answer';
  } else if (side === 'answer') {
    templateData.sideToShow = 'question';
    templateData.sideToShowDisplay = 'Question';
  }
  res.render('card', templateData);
});

module.exports = router;

This is in my card.pug file.

extends layout.pug

block content
  section#content
    h2= text
    //h3= answer
    if hint
      p
        i Hint: #{hint}
    a(href=`${id}?side=${sideToShow}`)= sideToShowDisplay

So why am I getting a 404?

Brian Anstett
Brian Anstett
5,831 Points

Hey Brian Patterson, can you post your app.js? Because you have taken advantage of the express.router() module in a separate file you need to make sure your application has a way to get to those routes either with a line like...

app.use(require('./path/to/router'));
// or something like this for more fine tune route organization
app.use('/cards', require('.path/to/router'));

Another suggestion I would have is change your link (a tag) in your card.pug file to an absolute link opposed to relative. Recall that relative paths are from your current location. This can cause problems if you're on a different page already.

 a(href=`/${id}?side=${sideToShow}`)= sideToShowDisplay
Brian Patterson
Brian Patterson
19,588 Points

Here is my app.js

const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

app.set('view engine', 'pug');

const mainRoutes = require('./routes');
const cardRoutes = require('./routes/cards');

app.use(mainRoutes);
app.use('/cards', cardRoutes);

app.use((req, res, next) => {
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
});

app.use((err, req, res, next) => {
  res.locals.error = err;
  const status = err.status || 500;
  res.status(status);
  res.render('error');
});

app.listen(3000, () => {
  console.log('The application is running on localhost:3000!');
});
Brian Patterson
Brian Patterson
19,588 Points

The problem seems to be the link. I have pretty much copied his code word for word and it still does not work.

http://localhost:3000/cards/4/4?side=answer

As you can see it is wrong it repeats the id. Dare I assume that his code is WRONG!

2 Answers

Brian Anstett
Brian Anstett
5,831 Points

Hey Brian, so currently the way you have it set up, you want to go to localhost://cards/{id}?side={something}, not localhost://{id}?side={something}. I'm not exactly sure what functionality is supposed to happen when you click on that link but just recall how "routes" work with express. With the route 'localhost://cards/4?side=answer', the following line in your app.js file matches the first part of the path, the "/cards".

app.use('/cards', cardRoutes);
//matches any route that starts with /cards
//localhost://cards/helloworld : matches
//localhost://cards/about :matches
//localhost://cards/****** :matches
//localhost://4?side=answer :does not match

Now that we matched all routes that start with '/cards', we tell our app to go check out 'cardRoutes' (./routes/cards) to match our path (url) with anything that comes after /cards.

so in our routes/cards.js

router.get('/:id', (req, res) => {}
//localhost://cards/4 :matches with req.prarms.id= 4 and req.query.side== null/undefined
//localhost://cards/4?side=answer :matches with req.prarms.id= 4 and req.query.side == 'answer'
//localhost://cards/about :matches with req.params.id == about and req.query.side == null/undefined

So in short, you just need to change your link in cards.pug to point to /cards/{id}?side={something here}

Brian Patterson
Brian Patterson
19,588 Points

how do I do that? This matches what he has in the tutorial.

Brian Patterson
Brian Patterson
19,588 Points

Thanks Brian Anstett. Still trying to get my head around this. I changed the pug file to the following.

a(href=`/cards/${id}?side=${sideToShow}`)= sideToShowDisplay

That seemed to work. Although, I am confused as to why it duplicated the id.

Brian Anstett
Brian Anstett
5,831 Points

I'm not sure why there's a double id either, I didn't watch the video. If you wanted a second id parameter in your route, you could just add the following in routes/cards.js.

router.get('/:id/:id2', (req, res, next)=>{})
//localhost://cards/4/5 :matches with req.params.id==4 and req.params.id2=5