Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am new to web apps and I am having a difficult time structuring my apps. I put together a very simple math web app which I wish to expand on. The app has the following pages/screens:

  • Home screen
  • About screen
  • Math question screen
  • Answer check screen
  • Results screen.

Right now the app works fine and is probably structured fine since it is very basic but I wish to expand on it in the future and want a solid foundation to build from. How can I improve the structure? I have researched this and it seems my best bet is to divide each screen into a separate folder (home folder - home.html, home.css, home.js... about folder...) then load the pages into a main page shell?

My code is below and on JS Bin: http://jsbin.com/ilukop/1/edit

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>App-to-Convert</title>

<script type="text/javascript">
    var field1 = 0;        //field1 and field2 are the values being added together
    var field2 = 0;
    var question_num = 0;  //question_num counts up to 10

    //The showPanel function displays the panel with the given id
    function showPanel(id) {
        //Check if 10 questions have been answered, then redirect to the "Done" screen
        if ((id=="question") && (question_num==10)) id="done";
        var panels = new Array("welcome","question","correct","incorrect","about","done");
        //Loop through and show the requested panel while hiding all of the others
        for (var i=0; i<panels.length; i++) {
            document.getElementById(panels[i]).style.display = (id==panels[i]) ? "block" : "none";
        }
        if (id=="welcome") {
            //Welcome screen resets the question number
            question_num = 0; 
        } else if (id=="question") {
            //Increment the question number
            ++question_num;
            //Create two random numbers
            field1 = Math.floor(Math.random() * 11);
            field2 = Math.floor(Math.random() * 11);
            //Show the two numbers on the screen
            document.getElementById("field1").innerHTML = field1;
            document.getElementById("field2").innerHTML = field2;
            //Clear the answer field and set the input focus
            var ans = document.getElementById("answer");
            ans.value = "";
            ans.focus();
        }
    }

    //The checkAnswer function compares the input to field1+field2 and shows correct or incorrect feedback
    function checkAnswer() {
        //Get the input
        var ans = document.getElementById("answer").value;
        //Show the "correct" panel if the input equals field1+field2, otherwise show "incorrect"
        showPanel((ans==(field1+field2)) ? "correct" : "incorrect");
    }
</script>

<style type="text/css">
#math_quiz {  /* main container */
    position: relative;
    width: 550px;
    height: 400px;
    font-family: 'Times New Roman', Times, serif;
    font-size: 24px;
    text-align: center;
    color: #121212;
}
#math_quiz p {
    margin-left: 40px;
    margin-right: 40px;
}
#math_quiz .field { /* the two numbers to be added */
    position: absolute;
    width: 75px;
    height: 27px;
    font-weight: bold;
    text-align: right;
}
#math_quiz .panel { /* each panel is 550x400 */
    position: absolute;
    left: 0px;
    top: 0px;
    width: 550px;
    height: 400px;
    display: none;    
}
#math_quiz a {   /* gold buttons with black borders */
    position: absolute;
    background-color: #FF9900;
    border: solid 5px #000000;
    color: #000000;
    font-weight: bold;
    text-decoration: none;
    padding: 10px 15px 10px 15px;
    display: block;
}
#math_quiz #plus_sign { /* static "+" sign */
    position:absolute;
    left:25px;
    top:127px;
    font-size:34px;
    font-weight:bold;
}
#math_quiz #horz_line { /* horizontal line above the answer */
    position:absolute;
    left:17px;
    top:167px;
    width:295px;
    height:5px;
    background-color:#000000;
}
#math_quiz #answer { /* input field */
    position:absolute;
    left:75px;
    top:182px;
    width:175px;
    height:32px;
    font-family:'Times New Roman', Times, serif;
    color:#121212;
    font-size:24px;
    font-weight:bold;
    text-align:right;
    border:solid 1px #000000;
    padding-right:5px;
}
</style>
</head>
<body bgcolor="#FFFFFF">
    <div id="math_quiz">
        <div id="welcome" class="panel" style="display:block">
            <h3>Math App</h3>
            <a style="left:21px;top:267px;" href="#" onClick="showPanel('question');return false;">Play Button</a>
            <a style="left:225px;top:268px;" href="#" onClick="showPanel('about');return false;">About Button</a>
        </div>
        <div id="question" class="panel">
            <div id="field1" class="field" style="left:170px;top:102px;"></div>
            <div id="field2" class="field" style="left:170px;top:132px;"></div>
            <div id="plus_sign">+</div>
            <div id="horz_line"></div>
            <input id="answer"/>
            <a style="left:182px;top:277px;" href="#" onClick="checkAnswer();return false;">OK Button</a>
        </div>
        <div id="correct" class="panel">
            <h3>Correct!</h3>
            <a style="left:210px;top:216px;" href="#" onClick="showPanel('question');return false;">OK Button</a>
        </div>
        <div id="incorrect" class="panel">
            <h3>Incorrect!</h3>
            <a style="left:210px;top:216px;" href="#" onClick="showPanel('question');return false;">OK Button</a>
        </div>
        <div id="about" class="panel">
            <p>About text would go here.</p>
            <a style="left:180px;top:277px;" href="#" onClick="showPanel('welcome');return false;">OK Button</a>
        </div>
        <div id="done" class="panel">
            <h3>You're done. You answered 10 questions.</h3>
            <a style="left:180px;top:277px;" href="#" onClick="showPanel('welcome');return false;">OK Button</a>
        </div>
    </div>
</body>
</html>
share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

If you organize the app into several pages/folders, then response will be slower, passing values around more complicated, and you will have several scripts instead of one to manage. So I would not do this until it becomes really too big to manage in a single page. Remember one of the key advantages of javascript is to get an immediate response to user actions instead of having to wait for a new page to load each time. Splitting it into separate pages would allow you to have a stable link to a particular screen (currently you can only link to the 'welcome' screen of your app), but that can also be implemented using javascript in a single page. If your app becomes an AJAX one, with server-side code as well as HTML/javascript, then separate pages might make more sense.

Without knowing how you intend to develop the app it is difficult to give specific advice, but usually it makes sense to organize the script into classes and objects rather than just functions. You could have an object panel for instance, capable of storing state internally and with appropriate methods.

Most developers also prefer setting event handlers within the script rather than in the HTML, as it is easier to see how things work and you can change event handlers if needed. The following is an example of how you might reorganize it (untested)

function Panel(id) {
    var el = document.getElementById(id), self = this;
    this.show = function() { 
        el.style.display = 'block';
        if (self.run) self.run();
    };
    this.hide = function() { el.style.display = 'none' };
    // can be extended
}
function Panels(ids) {
    var objs = {},
        questionNum = 0, 
        field1 = 0, 
        field2 = 0;
    for (var i = 0, id; id = ids[i]; i++) {
        objs[id] = new Panel(id);
        this[id] = getFunction(show, id);
    }
    // needed for reasons of variable scope:
    function getFunction(f, p) {return function() {f(p)}}
    function show(showId) {
        for (var i = 0, id; id = ids[i]; i++) {
            objs[id][id == showId ? 'show' : 'hide']();
        }
    }
    // You could add methods here that extend particular panels
    objs.welcome.run = function() {
        questionNum = 0;
    };
    objs.question.run = function() {
        ++ questionNum;
        // etc. Put all the logic for the question panel here
    };
}
panels = new Panels(["welcome","question","correct","incorrect","about","done"]);
// set event handlers here, e.g.
document.getElementById('playButton').onclick = panels.question; 

...
<a id="playButton">Play Button</a>
...

Given that you have lots of repetition in your HTML, it will probably also be better to build the panel display in javascript rather than only using the javascript to display/hide elements that are already in the page. (And note that this would be difficult to achieve if you split the app across several pages.)

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.