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 Build a REST API With Express Completing and Testing the API Test Routes with Postman

I can't get vote-up or down to work. This.parent(This isn't getting sent in the parameters)

Hi, I've been struggling for hours to fix my code. Can someone please look at it and see why the parameters don't seem to be getting sent correctly. Every time I try to use vote-up or vote-down it is just getting this.parent is not a function. I tried tons of different things to fix this, or just get a proper log to console to see, but everything is undefined in one way or another.

'use strict';
var express = require('express');
var router = express.Router();
var Question = require("./models.js").Question;

//questions param https://expressjs.com/en/api.html#app.param
router.param("qID", function(req,res,next,id){
    Question.findById(id, function(err, doc){
        if(err) return next(err);
        if(!doc){
            err = new Error("Not Found");
            err.status = 404;
            return next(err);
        }
        req.question = doc;
        return next();
    });

    //answers
router.param("aID", function(req,res,next,id){
    req.answer = req.question.answers.id(id);
    if(!req.answer){
        err = new Error("Not Found");
        err.status = 404;
        return next(err);
    }
    next(); 
});


});

//GET /questions
//route for getting questions
router.get("/", function(req,res,next){
        //  This is an alternative way to make a querey to get the questions and then sort them
    //Question.find({}, null, {sort: {createdAt: -1}}, function(err, questions){
    //     if(err) return next(err);
    //     res.json(questions);

    // });

    //Query builder 
    Question.find({})
        .sort({createdAt: -1})
        .exec(function(err, questions){
            if(err) return next(err);
            res.json(questions);
        });
});

//POST /questions
//Route for creating questions
router.post("/", function(req,res,next){
    var question = new Question(req.body);
    question.save(function(err, question){
        if (err) return next(err);
        res.status(201);
        res.json(question);

    });
});

//GET /questions
//route for getting a specfic question
router.get("/:qID", function(req,res,next){
        res.json(req.question);
});



//POST /questions/:id/answer
//Route for creating an answer
router.post("/:qID/answers", function(req,res,next){
    req.question.answers.push(req.body);
    req.question.save(function(err, question){
        if(err) return next(err);
        res.status(201);
        res.json(question);
    });
});

//PUT /questions/:qID/answers/:aID
//Edit a specific answer
router.put("/:qID/answers/:aID", function(req,res,next){
    req.answer.update(req.body, function(err, result){
        if(err) {return next(err)};
        res.json(result);
    });

});

//DELETE /questions/:qID/answers/:aID
//Delete a specific answer
router.delete("/:qID/answers/:aID", function(req,res,next){
    req.answer.remove(function(err){
        req.question.save(function(err, question){
            if(err){ return next(err)};
            res.json(question);
        });

    });

});


//POST /questions/:qID/answers/:aID/vote-up
//POST /questions/:qID/answers/:aID/vote-down
//Vote on a specific answer
router.post("/:qID/answers/:aID/vote-:dir", 
    function(req, res, next){
        if(req.params.dir.search(/^(up|down)$/) === -1) {
            var err = new Error("Not Found");
            err.status = 404;
            next(err);
        } else {
            req.vote = req.params.dir;
            next();
        }
    }, 
    function(req, res, next){
        req.answer.vote(req.vote, function(err, question){
            if(err) return next(err);
            res.json(question);
        });
});


module.exports = router; 

This is the models file

'use strict';

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var sortAnswers = function(a, b){
    // - negative a before b
    // 0 no change
    // + positive if a before b
    if(a.votes === b.votes){
        return b.updatedAt - a.updatedAt;
        // if(a.updatedAt > b.updatedAt){
        //     return -1;
        // }else if(a.updatedAt < b.updatedAt){
        //     return 1
        // }else{
        //     return 0;
        // }
    }
    return b.votes - a.votes;
};

var AnswerSchema = new Schema({
    text: String,
    createdAt: {type: Date, default: Date.now},
    updatedAt: {type: Date, default: Date.now},
    votes: {type: Number, default: 0}

});

AnswerSchema.method("update", (updates, callback) => {

    Object.assign(this, updates, {updatedAt: new Date()});
    this.parent().save(callback);

});

AnswerSchema.method("vote", (vote, callback)=>{
console.log(this)
    if(vote ==="up"){
        this.votes += 1;
    }else{
        this.votes -= 1;
    }

    this.parent().save(callback);

});

var QuestionSchema = new Schema({
    text: String,
    createdAt: {type: Date, default: Date.now},
    answers: [AnswerSchema]
});

//call save hook 
QuestionSchema.pre("save", function(next){
    this.answers.sort(sortAnswers);
    next();

});

var Question = mongoose.model("Question", QuestionSchema);

module.exports.Question = Question;

1 Answer

Try using a standard function in your 'AnswerSchema.vote' method. Functions which use the ES2015 arrow syntax don't have a binding for 'this'.

AnswerSchema.method("vote", function(vote, callback) {
    if (vote === "up") {
        this.votes += 1;
    } else {
        this.votes -= 1;
    }
    this.parent().save(callback);
});

Thank you so much, I spent so much time on that. I had know idea binding doesn't take place with es syntax. Wow, I am shocked with how many things I kept rewriting and trying and just couldn't understand. Thank You!