Taylor V
Taylor V

Reputation: 113

AJAX Form Post PreventDefault Not Working

I have a simple HTML document with a form I would like to post to the server without leaving the page. I've Googled around the internet all day trying to figure out how to get this to work and I've come up with the following code:

<body>
    <script> 
    $(document).ready(function() {

        $('#newResource').submit(function (e) {

            e.preventDefault();

            $.ajax({
                type: 'post',
                url: 'scripts/script.php?new-resource=1',
                data: $('#newResource').serialize(),
                success: function () {
                    alert('form was submitted');
                }
            });
            return false;

        });

    });
    </script>

    <form id="newResource" class="form-basic" enctype="multipart/form-data" method="post" action="scripts/script.php?new-resource=1">
        <label><b>Resource Name:</b></label>
        <input class="input-text" type="text" placeholder="Enter the resource name..." name="name" id="name" autocomplete="off" required="">
        <br>

        <label><b>Resource URL:</b></label>
        <input class="input-text" type="text" placeholder="Enter the resource URL..." name="url" id="url" autocomplete="off" required="">
        <br>

        <label><b>Resource Department:</b></label>
        <p>Select the department this resource should belong to.</p>
        <select class="input-select" name="department" id="department">
            <option value="5">Human Resources</option>
            <option value="1">Information Technology</option>
            <option value="3">Marketing</option>
            <option value="0">No Department</option>
            <option value="6">Purchasing</option>
            <option value="4">Sales</option>  
        </select>
        <br>

        <label><b>Resource Icon:</b></label>
        <p>Select the icon image to be displayed with this resource.</p>
        <select class="input-select" name="icon" id="icon">
            <option value="bell.png">Alarm Bell</option>
            <option value="chat-bubbles.png">Chat Bubbles</option>
            <option value="chronometer.png">Chronometer</option>
            <option value="database.png">Database Icon</option>
            <option value="envelope.png">Envelope</option>
            <option value="folder.png">File Folder</option>
            <option value="analytics.png">Monitor with Line Graph</option>
            <option value="pie-chart.png">Monitor with Pie Chart</option>
            <option value="networking.png">Networking Heirarchy</option>
            <option value="orientation.png">Orientation Arrow</option>
            <option value="server.png">Server Rack</option>
            <option value="settings.png">Settings Gears</option>
            <option value="speedometer.png">Speedomoeter</option>
            <option value="worldwide.png">World Wide Web Globe</option>
        </select>
        <br>

        <div style="float: right;">
            <button type="button" onclick="loadPrefs('resources');" class="form-button cancel">Cancel</button>
            <button class="form-button submit" type="submit">Submit</button>
        </div>

    </form>
</body>

The code is all within the body tag.

The problem is that when I click the submit button I am redirected to the PHP action script. Does the script I have need to be in the head tag instead?

If I remove the action from the form then the script redirects to the same page but no data is submitted.

Here is the PHP script if necessary:

if(isset($_GET['new-resource'])){

    // escape the SQL input for security
    $name = mysqli_real_escape_string($conn, $_POST['name']); 
    $url = mysqli_real_escape_string($conn, $_POST['url']); 
    $department = mysqli_real_escape_string($conn, $_POST['department']); 
    $icon = mysqli_real_escape_string($conn, $_POST['icon']); 

    // Run the SQL query to add the new resource item
    $sql = "INSERT INTO Resources (ID, ResourceName, ResourceURL, IconImg, Department) VALUES (NULL, '$name', '$url', '$icon', '$department');";
    $conn->query($sql);

    // Close the SQL connection
    $conn->close();

}

I can't seem to figure out why this is not working. Any thoughts and feedback are appreciated.

Upvotes: 0

Views: 3535

Answers (3)

Benni
Benni

Reputation: 1033

The important info in your case was "The HTML form elements are added with AJAX". At $(document).ready(), the #newResource form element did not yet exist, so the event was never bound. In your working example you used event delegation: $(document).on('click', '.submit', function(e) {...}, this is the correct way setup event listeners for non-existing elements.

Upvotes: 2

Taylor V
Taylor V

Reputation: 113

Ok, I've managed to get this following code to work:

<script type="text/javascript"> 
$(document).on('click', '.submit', function(e) { 

    debugger;

    e.preventDefault();

    var form = $(this).parent().closest('form');
    var action = form.attr('action');
    var data = form.serialize();


    $.ajax({
        type: 'POST',
        url: action,
        data: data,
        success: function () {
            loadPrefs('resources');
        }
    });
});
</script>

The HTML form elements are added with AJAX but so was the script element. I moved the script element to the top of the page so that it is static and no longer loaded with the form.

Upvotes: 0

Neil Girardi
Neil Girardi

Reputation: 4923

Your event handler is bound to the submit event of the form. By the time the form has been submitted, it's too late to stop the default synchronous HTML form submission.

Bind your handler to the to click event on the submit button, use event.preventDefault() and submit the form via Ajax:

$(document).ready(function() {

        $('.submit').click(function (e) {

            e.preventDefault();

            var form = $('#newResource');
            var action = form.attr('action');
            var data = form.serialize();


            $.ajax({
                type: 'POST',
                url: action,
                data: data,
                success: function () {
                    alert('form was submitted');
                }
            });


        });

    });

Please note, the way this is written, it will fire for any click of an element with a class of submit. Since you may have more than one form on your web page and more than one button with a class of submit, it's not good to have the form variable use a hard-coded ID selector.

If the HTML of all your website forms are always coded this same way, with the submit button inside of a div which is nested in the form, you could replace:

var form = $('#newResource');

with:

var form = $(this).parent().closest('form');

Now you can wrap that code in a function called "bindForms()" or whatever, and you have a generic recipe for handling all forms, provided that the HTML structure is always the same (or at least, to the extent that the submit button always has a class of submit and is always wrapped in a parent container which is a child of the form.

Upvotes: 0

Related Questions