Search code examples
javascriptnode.jsmongodbexpressglobal-variables

How to make a global variable or be able to access it in other files


So I have a nodejs project where I have a dynamic form which expands if the user clicks "add question". This functionality is done by my createUX.js file which has a function that appends more divs to the html form on buttonclick. The file also keeps track of the number of questions in a variable. Now I would like to access this variable in my create.js file which actually adds the questions to my database so I know how many questions to add. My createUX.js file under my public dir while my create.js file is under my routes directory. How can I achieve this? I already tried exporting the variable but it gave me the starting value for the variable. I also tried importing the whole file into a var and calling .questionNum on the file. Thank you!

createUX.js

var questionNum = 1; //starts at two because question 1 is already present

function addQuestion() {
    questionNum += 1;

    var questionSet = document.getElementById('questionSet');
    var question = document.createElement('div');
    var questionText = document.createElement('input');
    var answerA = document.createElement('input');
    var answerB = document.createElement('input');
    var answerC = document.createElement('input');
    var answerD = document.createElement('input');

    // setting up correct answer
    var correct = document.createElement('select');
    var choiceA = document.createElement('option');
    var choiceB = document.createElement('option');
    var choiceC = document.createElement('option');
    var choiceD = document.createElement('option');
    choiceA.setAttribute('value', 1)
    choiceB.setAttribute('value', 2)
    choiceC.setAttribute('value', 3)
    choiceD.setAttribute('value', 4)
    choiceA.innerHTML = 'A';
    choiceB.innerHTML = 'B';
    choiceC.innerHTML = 'C';
    choiceD.innerHTML = 'D';
    correct.appendChild(choiceA);
    correct.appendChild(choiceB);
    correct.appendChild(choiceC);
    correct.appendChild(choiceD);

    //set names
    question.setAttribute('id', 'question' + questionNum);
    questionText.setAttribute('name', 'questionText' + questionNum);
    answerA.setAttribute('name', questionNum + 'a' + 1);
    answerB.setAttribute('name', questionNum + 'a' + 2);
    answerC.setAttribute('name', questionNum + 'a' + 3);
    answerD.setAttribute('name', questionNum + 'a' + 4);
    correct.setAttribute('name', 'correct' + questionNum);

    //set input types
    questionText.setAttribute('type', 'text');
    answerA.setAttribute('type', 'text');
    answerB.setAttribute('type', 'text');
    answerC.setAttribute('type', 'text');
    answerD.setAttribute('type', 'text');

    //set placeholders
    questionText.setAttribute('placeholder', 'Question ' + questionNum);
    answerA.setAttribute('placeholder', 'Answer A');
    answerB.setAttribute('placeholder', 'Answer B');
    answerC.setAttribute('placeholder', 'Answer C');
    answerD.setAttribute('placeholder', 'Answer D');

    //append question text and answer to question div
    question.appendChild(document.createElement('br'));
    question.appendChild(questionText);
    question.appendChild(document.createElement('br'));
    question.appendChild(document.createElement('br'));
    question.appendChild(answerA);
    question.appendChild(answerB);
    question.appendChild(document.createElement('br'));
    question.appendChild(document.createElement('br'));
    question.appendChild(answerC);
    question.appendChild(answerD);
    question.appendChild(document.createElement('br'));
    question.appendChild(document.createElement('br'));

    //create and append label
    var label = document.createElement('label');
    label.innerHTML = 'Correct:&nbsp';
    question.appendChild(label);
    //continue appending rest of stuffs to question div
    question.appendChild(correct);
    question.appendChild(document.createElement('br'));
    question.appendChild(document.createElement('br'));

    //append question to current question set
    questionSet.appendChild(document.createElement('br'));
    questionSet.appendChild(question);
    questionSet.appendChild(document.createElement('br'));

    // have to remove and reappend the create button so that it appears at the end
    questionSet.removeChild(document.getElementById('createButton'));
    var createButton = document.createElement('button');
    createButton.setAttribute('id', 'createButton');
    createButton.innerHTML = 'Create Set'
    questionSet.appendChild(createButton);

    question.style.backgroundColor = randomColor();

}

//Called when user wants to exit quiz creator
function cancelQuiz() {
    if (confirm("Are you sure you want to exit? All work will be DELETED!")) {
        window.location.href = "../";
    }
}

function randomColor() {

    var colors = ['#4CAF50', '#f94a1e', '#3399ff', '#ff9933'];
    var randomNum = Math.floor(Math.random() * 4);
    return colors[randomNum];
}

function setBGColor() {
    var randColor = randomColor();
    document.getElementById('question1').style.backgroundColor = randColor;

}

create.js

const express = require('express');
const router = express.Router();

let Set = require('../models/set');
var numAnswers = 4; //how many answer choices do you want?

var createUX = require('../public/create/js/createUX');

module.exports = {

    createRender: (req, res) => {
        res.render('pages/create.ejs');
    },

    create: (req, res) => {

        var questionNum = createUX.questionNum;
        var title = req.body.title;
        var subtitle = req.body.subtitle;
        var descriptionTitle = req.body.descriptionTitle;
        var description = req.body.description;
        var photoRef = "";
        var questions = [];
        for (var i = 1; i <= questionNum; i++) {
            var questionText = req.body[`questionText${i}`];
            var answers = [];
            for (var j = 1; j <= 4; j++) {
                var answer = req.body[`${i}a${j}`];
                answers.push(answer);
            }
            var correct = req.body[`correct${i}`];
            var qtags = [];

            var question = { questionText, answers, correct, qtags };
            questions.push(question);
        }

        var sTags = []
        var creator = "Bao"
        var upvotes = "0"

        let newSet = new Set({
            title: title,
            subtitle: subtitle,
            descriptionTitle: descriptionTitle,
            description: description,
            photoRef: photoRef,
            questions: questions,
            sTags: sTags,
            creator: creator,
            upvotes: upvotes
        });

        var doc = db.collection('sets').insertOne(newSet);
        console.log('set created');
        res.redirect('/');
    }

}

create.ejs

<!DOCTYPE html>
<html>

<head>
    <title> Creator | KPRO </title>
    <link rel="stylesheet" href="../../public/create/css/create.css">
    <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet">
</head>

<body onload="setBGColor()">

    <!-- #2DO: Set word limit for titles/descriptions/questions/answers and make cap for how many questions you can add -->
    <form method="POST" action="/create" id="questionSet">

        <h1>Create Question Set</h1>
        <p>add cover image</p>
        <input type="text" name="title" placeholder="Title" autofocus required />
        <input type="text" name="subtitle" placeholder="Subtitle" autofocus required />
        <input type="text" name="descriptionTitle" placeholder="Description Title" autofocus required />
        <input type="text" name="description" placeholder="Description" autofocus required />
        <br>
        <br>
        <div id="question1">
            <br>
            <input name="questionText1" type="text" placeholder="Question 1" autofocus required />
            <br>
            <br>
            <input name="1a1" type="text" placeholder="Answer A" autofocus required />
            <input name="1a2" type="text" placeholder="Answer B" autofocus required />
            <br>
            <br>
            <input name="1a3" type="text" placeholder="Answer C" autofocus required />
            <input name="1a4" type="text" placeholder="Answer D" autofocus required />
            <br>
            <br>
            <label> Correct:&nbsp </label>
            <select name="correct1">
                <option value=1>A</option>
                <option value=2>B</option>
                <option value=3>C</option>
                <option value=4>D</option>
            </select>
            <br>
            <br>
        </div>

        <br>

        <button id='createButton'>Create Set</button>
    </form>
    <br>
    <button onclick="addQuestion()">Add another question</button>
    <br>
    <br>
    <button onclick='cancelQuiz()'>Cancel</button>

    <script src="../../socket.io/socket.io.js"></script>
    <script src="../../public/create/js/createUX.js"></script>
</body>

</html>

Solution

  • The questionNum variable is part of a "client side" script: a script that runs in the browser of your users. So, as the definitive value of questionNum is set in the browser, you have to send its value back to the server.

    You can do it by adding a hidden field to your form and make addQuestion function increment its value.

    In the form:

    <input type="hidden" id="questionNum" name="questionNum" value="1">
    

    In addQuestion:

    ​var questionNum = document.getElementById("questionNum").value;
    questionNum = Number(questionNum);
    questionNum +=1;
    document.getElementById("questionNum").value = questionNum;
    

    Then get its value back in create.js:

    module.exports = {
    
        create: (req, res) => {
    
            var questionNum = req.body.questionNum;