User Tools

Site Tools


en:web_development:forms:javascript

This is an old revision of the document!


Web Developent Lesson 8 - Forms

Javascript

Objectives

In this activity you'll learn to use Javascript to

  • temporarily display status messages
  • check form inputs before submitting

Setup

  • We'll continue using 'form.php', 'process_form.php' and 'style.css', which are reproduced below in case you need them.
  • We'll also need a file for Javascript, so create a file called 'form.js' in the same directory as 'form.php'.

form.php

<?php
    include('database.php');

    include('header.php');
    include('menu.php');

    // get list of heroes
    $query = "SELECT * FROM heroes";
    $args  = array();
    $hrslt = $pdo->prepare($query);
    $hrslt->execute($args);

    // get list of movies
    $query = "SELECT movie FROM appearances GROUP BY movie";
    $args  = array();
    $mrslt = $pdo->prepare($query);
    $mrslt->execute($args);
?>
    <main>
        <form name="add_hero" action="process_form.php" method="post">
            <fieldset>
                <legend>Add Hero</legend>
                <ul>
                    <li>
                        <label>Alias:</label>
                        <input type="text" name="alias" size="30" maxlength="50" hint="Iron Man">
                    </li>
                    <li>
                        <label>Identity:</label>
                        <input type="text" name="identity" size="30" maxlength="50" hint="Tony Stark">
                    </li>
                    <li>
                        <label>Side:</label>
                        <ul>
                            <li><input type="radio" name="side" value="Hero" checked> Hero</li>
                            <li><input type="radio" name="side" value="Villain"> Villain</li>
                        </ul>
                    </li>
                    <li>
                        <label>First Appearance:</label>
                        <input type="number" name="year">
                    </li>
                    <li>
                        <label>Source of Power:</label>
                        <select name="power">
                            <option value="Skill">Skill</option>
                            <option value="Biological">Biological</option>
                            <option value="Magic">Magic</option>
                            <option value="Technology">Technology</option>
                            <option value="Mutant">Mutant</option>
                        </select>
                    </li>
                </ul>
                <input type="submit" name="submit" value="Add / Update Hero">
            </fieldset>
        </form>

        <form name="add_appearances" action="process_form.php" method="post">
            <fieldset>
                <legend>Add Appearances</legend>
                <ul>
                    <li>
                        <label>Hero</label>
                        <select name="alias">
<?php
    // display list of heroes
    while($row = $hrslt->fetch()) {
?>
                            <option value="<?php echo $row['alias']; ?>"><?php echo $row['alias']; ?></option>
<?php
    }
?>
                        </select>
                    </li>
                    <li>
                        <label>Movie</label>
                        <ul>
<?php
    // display list of movies
    while($row = $mrslt->fetch()) {
?>
                            <li><input type="checkbox" name="movie[]" value="<?php echo $row['movie']; ?>" id=""> <?php echo $row['movie']; ?></li>
<?php
    }
?>
                            <li><input type="checkbox" name="movie[]" value="new" id=""> <input type="text" name="new_movie"></li>
                        </ul>
                    </li>
                </ul>
                <input type="submit" name="submit" value="Add Appearance">
                <input type="submit" name="submit" value="Delete Appearances">
            </fieldset>
        </form>
    </main>
<?php
    include('footer.php');
?>

process_form.php

<?php
    include('header.php');
    include('menu.php');
    include('database.php');
    
    // check which form
    switch ($_POST['submit']) {
        case 'Add / Update Hero':
            // check whether hero already exists
            $hquery = "SELECT * FROM heroes WHERE alias=?";
            $hargs  = array($_POST['alias']);
            $hrslt  = $pdo->prepare($hquery);
            $hrslt->execute($hargs);
            if($row = $hrslt->fetch()) { // the hero exists
                $query = "UPDATE heroes SET identity=?, hero_villain=?, first_appeared=?, power=? WHERE alias=?";
                $args  = array($_POST['identity'], $_POST['side'], $_POST['year'], $_POST['power'], $_POST['alias']);
                $rslt  = $pdo->prepare($query);
                if($rslt->execute($args)) {
                    $message = "{$_POST['alias']} was updated successfully.";
                } else {
                    $message = "There was a problem updating {$_POST['alias']}.";
                }
            } else {
                $query = "INSERT INTO `heroes` (`alias`, `identity`, `hero_villain`, `first_appeared`, `power`) VALUES (?,?,?,?,?)";
                $args  = array($_POST['alias'], $_POST['identity'], $_POST['side'], $_POST['year'], $_POST['power']);
                $rslt  = $pdo->prepare($query);
                if ($rslt->execute($args)) {
                    $message = "{$_POST['alias']} was inserted successfully.";
                } else {
                    $message = "There was a problem inserting {$_POST['alias']}.";
                }
            }
            break;
        case 'Add Appearance':
            $args = array();
            foreach($_POST['movie'] as $movie) {
                if ($movie == 'new') {
                    array_push($args, $_POST['alias'], $_POST['new_movie']);
                } else {
                    error_log($movie);
                    // check if it exists already
                    $mquery = "SELECT * FROM appearances WHERE alias=? AND movie=?";
                    $margs  = array($_POST['alias'], $movie);
                    $rslt   = $pdo->prepare($mquery);
                    $rslt->execute($margs);
                    if (!$row = $rslt->fetch()) {
                        array_push($args, $_POST['alias'], $movie);
                    }
                }
            }
            error_log(print_r($args, 1));
            $movies = count($args)/2;
            if ($movies > 0) {
                $values = str_repeat('(?,?), ', $movies-1) . '(?,?)';
                $query = "INSERT INTO appearances (alias, movie) VALUES $values";
                error_log("MURRAY: $query    " . print_r($args, 1));
                $rslt  = $pdo->prepare($query);
                if ($rslt->execute($args)) {
                    $message = "$movies appearances were inserted successfully.";
                } else {
                    $message = "There was a problem inserting $movies appearances.";
                }
            } else {
                $checked = count($_POST['movie']);
                $message = "All $checked appearances are already in the database.";
            }
            
            break;
        case 'Delete Appearances':
            $movies = count($_POST['movie']);
            $values = str_repeat('?,', $movies-1) . '?';
            $query = "DELETE FROM appearances WHERE alias=? AND movie IN ($values)";
            $args  = array($_POST['alias']);
            foreach($_POST['movie'] as $movie) {
                array_push($args, $movie);
            }
            error_log($query . print_r($args, 1));
            $rslt = $pdo->prepare($query);
            if ($rslt->execute($args)) {
                $message = "$movies appearances were deleted successfully.";
            } else {
                $message = "There was a problem deleting $movies appearances";
            }
            break;
        default:
            break;
    }
?>
    <main>
        <p><?php echo $message; ?></p>
    </main>
<?php
    include('footer.php');
?>

style.css

ol {
    color: blue;
  }
  
  ol ol {
    font-weight: 700;
  }

ul {
  list-style-type: none;
}

td, th {
  border-width: 1px;
  border-style: solid;
}

td {
  padding: 10px;
}

table {
  border-collapse: collapse;
}

header {
  background-color:indianred;
  border:darkred solid 2px;
  height: 100px;
  position: absolute;
  left: 16%;
  right: 0px;
  top: 0px;
}

nav {
  background-color: burlywood;
  border:yellow solid 2px;
  position: fixed;
  top: 0px;
  bottom: 0px;
  width: 16%;
  left: 0px;
}

main {
  background-color: lightgree;
  border: darkgreen solid 2px;
  position: absolute;
  top: 100px;
  left: 16%;
  right: 0px;
  bottom: 80px;
  overflow: scroll;
  padding: 20px;
}

footer {
  background-color: lightskyblue;
  border: darkblue solid 2px;
  position: absolute;
  bottom: 0px;
  height: 80px;
  left: 16%;
  right: 0px;
}

.content {
  background-color:coral;
  border:orangered solid 2px;
  height: 400px;
  padding: 40px;
  margin: 20px;
  display: inline-block;
  width: 300px;
}

img {
  float: left;
  max-height: 250px;
  border: solid 2px green;
  margin: 20px 20px 20px 0px;
  padding: 10px;
  border-radius: 30px;
}

#album {
  display: flex;
  justify-content:space-between;
  flex-wrap: wrap;
}

video {
  max-height: 250px;
  float: right;
  clear: left;
  margin: 20px 0px 20px 20px;
  padding: 10px;
}

audio {
  margin: 20px 20px 20px 0px;
  padding: 10px 10px 10px 0px;
}

input[type=button] {
  display: block;
}

figcaption {
  display: block;
  text-align: center;
  font-family: 'Arial', sans-serif;
  color: green;
}

label {
  display: inline-block;
  width: 10em;
  text-align: right;
}

input[type=checkbox], input[type=radio] {
  margin-left: 11em;
}

input[type=text], input[type=number], select {
  margin-left: 1em;
}

input[name=new_movie] {
  margin-left: 0em;
}

Single Page Form and Processing

  • Sometimes separating the form from the processing as we've done makes sense because the form is only required once and then you'll show them something different.
  • More often, in my experience, a form adds to existing content that you'll show after submission, so it makes more sense to include the processing code on the same page as the form.
  • We'll do this now. Copy everything in 'process_form.php' excluding the include lines and html code to the top of 'form.php'.
  • 'form.php' should now look like this.
<?php
    include('database.php');
    // check which form
    switch ($_POST['submit']) {
        case 'Add / Update Hero':
            // check whether hero already exists
            $hquery = "SELECT * FROM heroes WHERE alias=?";
            $hargs  = array($_POST['alias']);
            $hrslt  = $pdo->prepare($hquery);
            $hrslt->execute($hargs);
            if($row = $hrslt->fetch()) { // the hero exists
                $query = "UPDATE heroes SET identity=?, hero_villain=?, first_appeared=?, power=? WHERE alias=?";
                $args  = array($_POST['identity'], $_POST['side'], $_POST['year'], $_POST['power'], $_POST['alias']);
                $rslt  = $pdo->prepare($query);
                if($rslt->execute($args)) {
                    $message = "{$_POST['alias']} was updated successfully.";
                } else {
                    $message = "There was a problem updating {$_POST['alias']}.";
                }
            } else {
                $query = "INSERT INTO `heroes` (`alias`, `identity`, `hero_villain`, `first_appeared`, `power`) VALUES (?,?,?,?,?)";
                $args  = array($_POST['alias'], $_POST['identity'], $_POST['side'], $_POST['year'], $_POST['power']);
                $rslt  = $pdo->prepare($query);
                if ($rslt->execute($args)) {
                    $message = "{$_POST['alias']} was inserted successfully.";
                } else {
                    $message = "There was a problem inserting {$_POST['alias']}.";
                }
            }
            break;
        case 'Add Appearance':
            $args = array();
            foreach($_POST['movie'] as $movie) {
                if ($movie == 'new') {
                    array_push($args, $_POST['alias'], $_POST['new_movie']);
                } else {
                    error_log($movie);
                    // check if it exists already
                    $mquery = "SELECT * FROM appearances WHERE alias=? AND movie=?";
                    $margs  = array($_POST['alias'], $movie);
                    $rslt   = $pdo->prepare($mquery);
                    $rslt->execute($margs);
                    if (!$row = $rslt->fetch()) {
                        array_push($args, $_POST['alias'], $movie);
                    }
                }
            }
            error_log(print_r($args, 1));
            $movies = count($args)/2;
            if ($movies > 0) {
                $values = str_repeat('(?,?), ', $movies-1) . '(?,?)';
                $query = "INSERT INTO appearances (alias, movie) VALUES $values";
                error_log("MURRAY: $query    " . print_r($args, 1));
                $rslt  = $pdo->prepare($query);
                if ($rslt->execute($args)) {
                    $message = "$movies appearances were inserted successfully.";
                } else {
                    $message = "There was a problem inserting $movies appearances.";
                }
            } else {
                $checked = count($_POST['movie']);
                $message = "All $checked appearances are already in the database.";
            }
            
            break;
        case 'Delete Appearances':
            $movies = count($_POST['movie']);
            $values = str_repeat('?,', $movies-1) . '?';
            $query = "DELETE FROM appearances WHERE alias=? AND movie IN ($values)";
            $args  = array($_POST['alias']);
            foreach($_POST['movie'] as $movie) {
                array_push($args, $movie);
            }
            error_log($query . print_r($args, 1));
            $rslt = $pdo->prepare($query);
            if ($rslt->execute($args)) {
                $message = "$movies appearances were deleted successfully.";
            } else {
                $message = "There was a problem deleting $movies appearances";
            }
            break;
        default:
            break;
    }

    include('header.php');
    include('menu.php');

    // get list of heroes
    $query = "SELECT * FROM heroes";
    $args  = array();
    $hrslt = $pdo->prepare($query);
    $hrslt->execute($args);

    // get list of movies
    $query = "SELECT movie FROM appearances GROUP BY movie";
    $args  = array();
    $mrslt = $pdo->prepare($query);
    $mrslt->execute($args);
?>
    <main>
        <form name="add_hero" action="process_form.php" method="post">
            <fieldset>
                <legend>Add Hero</legend>
                <ul>
                    <li>
                        <label>Alias:</label>
                        <input type="text" name="alias" size="30" maxlength="50" hint="Iron Man">
                    </li>
                    <li>
                        <label>Identity:</label>
                        <input type="text" name="identity" size="30" maxlength="50" hint="Tony Stark">
                    </li>
                    <li>
                        <label>Side:</label>
                        <ul>
                            <li><input type="radio" name="side" value="Hero" checked> Hero</li>
                            <li><input type="radio" name="side" value="Villain"> Villain</li>
                        </ul>
                    </li>
                    <li>
                        <label>First Appearance:</label>
                        <input type="number" name="year">
                    </li>
                    <li>
                        <label>Source of Power:</label>
                        <select name="power">
                            <option value="Skill">Skill</option>
                            <option value="Biological">Biological</option>
                            <option value="Magic">Magic</option>
                            <option value="Technology">Technology</option>
                            <option value="Mutant">Mutant</option>
                        </select>
                    </li>
                </ul>
                <input type="submit" name="submit" value="Add / Update Hero">
            </fieldset>
        </form>

        <form name="add_appearances" action="process_form.php" method="post">
            <fieldset>
                <legend>Add Appearances</legend>
                <ul>
                    <li>
                        <label>Hero</label>
                        <select name="alias">
<?php
    // display list of heroes
    while($row = $hrslt->fetch()) {
?>
                            <option value="<?php echo $row['alias']; ?>"><?php echo $row['alias']; ?></option>
<?php
    }
?>
                        </select>
                    </li>
                    <li>
                        <label>Movie</label>
                        <ul>
<?php
    // display list of movies
    while($row = $mrslt->fetch()) {
?>
                            <li><input type="checkbox" name="movie[]" value="<?php echo $row['movie']; ?>" id=""> <?php echo $row['movie']; ?></li>
<?php
    }
?>
                            <li><input type="checkbox" name="movie[]" value="new" id=""> <input type="text" name="new_movie"></li>
                        </ul>
                    </li>
                </ul>
                <input type="submit" name="submit" value="Add Appearance">
                <input type="submit" name="submit" value="Delete Appearances">
            </fieldset>
        </form>
    </main>
<?php
    include('footer.php');
?>
  • For this to work, we need to direct the forms to this page when submitted.
  • Update the action in each form to 'form.php'.
        <form name="add_hero" action="form.php" method="post">
        <form name="add_appearances" action="form.php" method="post">
  • We're missing a place to display the status message. Add a tag at the top of <main>.
        <div id="status">
            <p><?php echo $message; ?></p>
        </div>
  • Save, upload and check that you can see the message.
  • Then let's add some CSS to make it clear it's a status message.
#status {
  background-color: rgb(238, 157, 157);
  border: darkred 1px solid;
  color: darkred;
  margin-bottom: 20px;
  padding-left: 20px;
}
  • The colours make it stand out, and the margin and padding give it some space to make it readable.
  • Save and upload the files and submit something to ensure you're happy with the way it looks. Feel free to change it until you are.

Timer

  • We need to link Javascript, which we can do simply by naming the page because we've added a link in 'header.php' already to link Javascript for each page.
    $page = "form";
    include('header.php');
  • Open 'form.js'.
  • We'll want the message to show (if there is one) for a short time, then make it disappear.
  • There's no point doing this until the page is ready, so we'll set our code to run on window.onload.
window.onload = function () {
    
}
  • Let's name the tag so we don't have to keep typing out the full code.
window.onload = function () {
    var status = document.getElementById('status');
}
  • Now we want to set a timer for 10 seconds (or choose a time that suits you).
  • Unlike PHP and most other languages, Javascript doesn't wait for each line of code to execute before moving on. It sets a line of code to run and then goes immediately on to the next. This means that code saying 'wait for 10 seconds' won't have any effect.
  • Instead, we put the code we want to delay inside a function and use setTimeout to wait 10s before running the function.
  • Javascript counts in milliseconds, so 10s is 10000.
  • Add this code after setting 'status'.
    setTimeout(function () {

    }, 10000);
  • This says to wait 10000ms then run the function inside {} .
  • In our case, our function is simply to remove the 'status' div from the page.
  • Add this inside the {} .
        status.style.display = 'none';
  • Save and upload the code, then run to see the effect.
  • The code disappears after 10s as we want, but if there's no message, it shows an ugly red block for 10s, which isn't a great user experience.
  • Let's hide the status using CSS.
#status {
  background-color: rgb(238, 157, 157);
  border: darkred 1px solid;
  color: darkred;
  margin-bottom: 20px;
  padding-left: 20px;
  display: none;
}
  • Then we can use Javascript to display the status if it actually has content.
window.onload = function () {
    var status = document.getElementById('status');
    if (status.firstElementChild.innerHTML != '') {
        status.style.display = 'block';
    }
    setTimeout(function () {
        status.style.display = 'none';
    }, 10000);
}
  • The new lines (3-5) check whether there is any code inside the <p> element (the firstChildElement of 'status'), and if so, sets the display to 'block'.
  • Save and upload the code to make sure it works to your satisfaction.

Form Verification

  • Remember that we added some code in the 'Add Appearances' form to check whether there were any movies to add?
  • We did that to avoid sending a bad query to the database.
  • In a large system, many bad queries will slow down the site for everyone, which makes for a bad experience.
  • We therefore want to check everything before sending it on. We should also have done this for the 'Add Hero' form, but I usually do this step last because if it's better not to send a bad query to the database, it's also better not to send bad data to the server.
  • We can use Javascript on the user's PC to check that data is good before sending the data to the server.
  • To do this, we can catch the 'submit' requests and hold it until we're ready, but it's simpler to change the 'submit' input to a 'button' input. Do this for all our 'submit' inputs.
                <input type="button" name="submit" value="Add / Update Hero">
                <input type="button" name="submit" value="Add Appearance">
                <input type="button" name="submit" value="Delete Appearances">
  • Then we can call functions for each to verify the data and submit when we're ready.
                <input type="button" name="submit" value="Add / Update Hero" onclick="verifyAddHero()">
                <input type="button" name="submit" value="Add Appearance" onclick="verifyAddAppearance()">
                <input type="button" name="submit" value="Delete Appearances" onclick="verifyDeleteAppearance()">
en/web_development/forms/javascript.1643123188.txt.gz · Last modified: 2023/08/16 09:33 (external edit)