0

I'm doing a simple PHP quiz app which uses jquery, the rules are:

  1. each quiz has many questions (max 100), user clicks to add more questions, which generates a new form, appended at the end of the list
  2. many answers for each question (max 5), user clicks to add more answers for a question, appended at the end of the answer list of that question
  3. questions are sorted/weighted by submit sequence, ajax post in this case
  4. answers are named "answer[]"
  5. The quiz loaded from db, user can remove, edit or add new questions/answers within above limits

I've decided to organized each question a form with "class='postable'". My script for quiz updating looks like this

$("#update-change").click(function(e){
    e.preventDefault();
    showupdate('Updating..');

       $('form.postable').each(function(){
           $.ajax({
                 type: "POST",
                 url: 'update_ask.php',

                 data: $(this).serialize()
            }).done(function( msg ) {
                feedbackMessage(msg);
            });
       });
});

So, each time "#update-change" hit, there are n ajax posted to 'update_ask.php' to save quiz contents. The problem is the questions won't be sorted as seeing, it could be 'update_ask.php' fail to process ajax request in sequence due to lagging.

Do you have any idea/solution for this case? Please advise. Thanks.

HTML for one question sets looks like this:

<form action="update_ask.html" method="post" accept-charset="utf-8" name="aj_edit_ask2430" id="editaskform2430" class="postable">
    <input type="hidden" name="idask" value="2430" />
    <input type="hidden" name="idquiz" value="240" />
    <div class="ask-holder">
        <textarea name="ask" class="ask"  tabindex="24300" placeholder="Question">cau 5</textarea>
        <div class="right answer-image-holder"><img src="no-image.jpg" id="askimg2430" class="answerimg" alt="image" />
            <input type="hidden" name="askimg" id="saskimg2430" value="" />
        </div>
    </div>
    <div id="solution2430" class="answer-holder">
        <div id="answer30684" class="answer-row">
            <textarea name="answer[]" class="answer" tabindex="24301" placeholder="Answer or Solution">answer 51</textarea>
            <div class="right answer-image-holder"> <img src="no-image.jpg" id="img30684" class="answerimg" alt="image" />
            <input type="hidden" name="images[]" id="simg30684" value="" />
            </div>
            <span>
            <input type="radio" name="iscorrect" value="1" checked='checked'  />
            Correct <a href="#row2430" onclick="removeAnswer('30684')" title="Remove this solution" class="removeanswer">Delete</a></span>
        </div>
        <div id="answer30685" class="answer-row">
            <textarea name="answer[]" class="answer" tabindex="24302" placeholder="Answer or Solution">answer 52</textarea>
            <div class="right answer-image-holder"> <img src="no-image.jpg" id="img30685" class="answerimg" alt="image" />
                <input type="hidden" name="images[]" id="simg30685" value="" />
            </div>
            <span>
            <input type="radio" name="iscorrect" value="2"   />
            Correct <a href="#row2430" onclick="removeAnswer('30685')" title="Remove this solution" class="removeanswer">Delete</a></span>
         </div>
        <div id="answer30686" class="answer-row">
            <textarea name="answer[]" class="answer" tabindex="24303" placeholder="Answer or Solution">answer 53</textarea>
            <div class="right answer-image-holder"> <img src="no-image.jpg" id="img30686" class="answerimg" alt="image" />
                <input type="hidden" name="images[]" id="simg30686" value="" />
            </div>
            <span>
            <input type="radio" name="iscorrect" value="3"   />
            Correct <a href="#row2430" onclick="removeAnswer('30686')" title="Remove this solution" class="removeanswer">Delete</a></span>
         </div>
    </div>
    <a href="#row2430" onclick="return addSolution('2430')" title="Add one more solution">Add</a> <a href="#row2430" onclick="return removeAsk('2430','order2430')" title="Completely Delete this question">Delete this question</a>
</form>
4
  • Is there any good reason to make each question its own form? I'm thinking it would be much more appropriate to put all the questions on one form, and just post that via one AJAX call, instead of (potentially) 100. Commented May 2, 2013 at 16:13
  • @Travesty3, yes, there are many other properties of each answer (image, true or false, weight ..) which make the form complicated. Commented May 2, 2013 at 16:19
  • Process each form (by index perhaps?), posting the ajax, then process the next form on completion of that ajax success/done Commented May 2, 2013 at 17:22
  • @Mark, could you please elaborate more on your solution? I'm facing difficulty in using ajaxStop inside .each loop. Commented May 3, 2013 at 4:50

2 Answers 2

1

Putting each question in its own form and making an AJAX request for each question on the page seems like a bad idea. That would be a ton of overhead, making up to 100 server requests every time the user hits a button. You should put all the questions on one form.

As for the extra complications that make you think one form is necessary for each question, I'm betting that it can still be done with one form for all questions...but you'll have to post a code sample that shows that complication before I can help there.


UPDATE:

Having the extra stuff associated with each question doesn't mean that you need to use one form for every question. It just means that you need to revise your naming convention for your elements. Based on the HTML you provided, you could change it to something more like this (notice the changes in the names of the form elements):

<form action="update_ask.html" method="post" accept-charset="utf-8">
    <input type="hidden" name="questions[0][idquiz]" value="240" />
    <div id="question-2430">
        <input type="hidden" name="questions[0][idask]" value="2430" />
        <div class="ask-holder">
            <textarea name="questions[0][ask]" class="ask"  tabindex="24300" placeholder="Question">cau 5</textarea>
            <div class="right answer-image-holder"><img src="no-image.jpg" id="askimg2430" class="answerimg" alt="image" />
                <input type="hidden" name="questions[0][askimg]" id="saskimg2430" value="" />
            </div>
        </div>
        <div id="solution2430" class="answer-holder">
            <div id="answer30684" class="answer-row">
                <textarea name="questions[0][answers][]" class="answer" tabindex="24301" placeholder="Answer or Solution">answer 51</textarea>
                <div class="right answer-image-holder">
                    <img src="no-image.jpg" id="img30684" class="answerimg" alt="image" />
                    <input type="hidden" name="questions[0][images][]" id="simg30684" value="" />
                </div>
                <span>
                    <input type="radio" name="questions[0][iscorrect]" value="1" checked='checked'  /> Correct
                    <a href="#row2430" onclick="removeAnswer('30684')" title="Remove this solution" class="removeanswer">Delete</a>
                </span>
            </div>
            <div id="answer30685" class="answer-row">
                <textarea name="questions[0][answers][]" class="answer" tabindex="24302" placeholder="Answer or Solution">answer 52</textarea>
                <div class="right answer-image-holder">
                    <img src="no-image.jpg" id="img30685" class="answerimg" alt="image" />
                    <input type="hidden" name="questions[0][images][]" id="simg30685" value="" />
                </div>
                <span>
                    <input type="radio" name="questions[0][iscorrect]" value="2"   /> Correct
                    <a href="#row2430" onclick="removeAnswer('30685')" title="Remove this solution" class="removeanswer">Delete</a>
                </span>
             </div>
            <div id="answer30686" class="answer-row">
                <textarea name="questions[0][answers][]" class="answer" tabindex="24303" placeholder="Answer or Solution">answer 53</textarea>
                <div class="right answer-image-holder">
                    <img src="no-image.jpg" id="img30686" class="answerimg" alt="image" />
                    <input type="hidden" name="questions[0][images][]" id="simg30686" value="" />
                </div>
                <span>
                    <input type="radio" name="questions[0][iscorrect]" value="3"   /> Correct
                    <a href="#row2430" onclick="removeAnswer('30686')" title="Remove this solution" class="removeanswer">Delete</a>
                </span>
             </div>
        </div>
        <a href="#row2430" onclick="return addSolution('2430')" title="Add one more solution">Add</a>
        <a href="#row2430" onclick="return removeAsk('2430','order2430')" title="Completely Delete this question">Delete this question</a>
    </div>
    <div id="question-2431">
        <input type="hidden" name="questions[1][idask]" value="2431" />
        <div class="ask-holder">
            <textarea name="questions[1][ask]" class="ask"  tabindex="24310" placeholder="Question">cau 5</textarea>
            <div class="right answer-image-holder"><img src="no-image.jpg" id="askimg2431" class="answerimg" alt="image" />
                <input type="hidden" name="questions[1][askimg]" id="saskimg2431" value="" />
            </div>
        </div>
        <div id="solution2431" class="answer-holder">
            <div id="answer30684" class="answer-row">
                <textarea name="questions[1][answers][]" class="answer" tabindex="24311" placeholder="Answer or Solution">answer 51</textarea>
                <div class="right answer-image-holder">
                    <img src="no-image.jpg" id="img30684" class="answerimg" alt="image" />
                    <input type="hidden" name="questions[1][images][]" id="simg30684" value="" />
                </div>
                <span>
                    <input type="radio" name="questions[1][iscorrect]" value="1" checked='checked'  /> Correct
                    <a href="#row2431" onclick="removeAnswer('30684')" title="Remove this solution" class="removeanswer">Delete</a>
                </span>
            </div>
            <div id="answer30685" class="answer-row">
                <textarea name="questions[1][answers][]" class="answer" tabindex="24312" placeholder="Answer or Solution">answer 52</textarea>
                <div class="right answer-image-holder">
                    <img src="no-image.jpg" id="img30685" class="answerimg" alt="image" />
                    <input type="hidden" name="questions[1][images][]" id="simg30685" value="" />
                </div>
                <span>
                    <input type="radio" name="questions[1][iscorrect]" value="2"   /> Correct
                    <a href="#row2431" onclick="removeAnswer('30685')" title="Remove this solution" class="removeanswer">Delete</a>
                </span>
             </div>
            <div id="answer30686" class="answer-row">
                <textarea name="questions[1][answers][]" class="answer" tabindex="24313" placeholder="Answer or Solution">answer 53</textarea>
                <div class="right answer-image-holder">
                    <img src="no-image.jpg" id="img30686" class="answerimg" alt="image" />
                    <input type="hidden" name="questions[1][images][]" id="simg30686" value="" />
                </div>
                <span>
                    <input type="radio" name="questions[1][iscorrect]" value="3"   /> Correct
                    <a href="#row2431" onclick="removeAnswer('30686')" title="Remove this solution" class="removeanswer">Delete</a>
                </span>
             </div>
        </div>
        <a href="#row2431" onclick="return addSolution('2431')" title="Add one more solution">Add</a>
        <a href="#row2431" onclick="return removeAsk('2431','order2431')" title="Completely Delete this question">Delete this question</a>
    </div>
    <input type="submit" value="Update" />
</form>

<script>
    $('form').submit(function(e) {
        e.preventDefault();
        showupdate('Updating...');

        $.ajax({
            type: 'POST',
            url: 'update_ask.php',
            data: $(this).serialize(),
            success: function(msg) {
                feedbackMessage(msg);
            }
        });
    });
</script>

And now your PHP might look something like this:

$quizID = $_POST['idquiz'];

$questions = $_POST['questions'];
var_dump($questions);

/*
This will look something like:
array(
    [0] => array(
        'answers' => array('answer 51', 'answer 52', 'answer 53'),
        'ask' => 'cau 5',
        'askimg' => '',
        'idask' => '2430',
        'images' => array('', '', ''),
        'iscorrect' => '1'
    ),
    [1] => array(
        'answers' => array('answer 51', 'answer 52', 'answer 53'),
        'ask' => 'cau 5',
        'askimg' => '',
        'idask' => '2431',
        'images' => array('', '', ''),
        'iscorrect' => '1'
    )
)
*/
Sign up to request clarification or add additional context in comments.

4 Comments

thank you for your help. Of course using one form is the first solution, but the 'quiz editing interface' is quite complicate to put all elements on one form. Please see my sample html
@TuyenDuy: See updated answer. This will be MUCH faster than 100 AJAX calls, and easier to work with.
The initial investment of revising your HTML generation to match this new naming convention might make you shy away from this solution, but trust me, if you keep doing up to 100 form submissions every time the user clicks the update button, you will regret not taking the time to implement a better solution.
Thanks, Travesty. I must invest in revising the mechanism like your advice. It's dumb to flood the server with too many requests.
0

Per request, this example uses jQuery Deferred to process all the forms, rework that last function to your needs/how to react to failures of posts. Note no ajaxStop needed as the events are managed by the deferreds.

$('#update-change').on('click', function (event) {
    var forms = $('form.postable');
    event.preventDefault();
    var quizIndex = 0;
    var countOfForms = forms.length;
    for (quizIndex = 0; quizIndex < countOfForms; quizIndex++) {
        saveQuiz(forms, quizIndex);
    }
});

function quizPost(quiz, dfd) {
    $.ajax({
        type: "POST",
        url: 'update_ask.php',
        dataType: "json",
        data: quiz.serialize(),
        success: dfd.resolve,
        error: dfd.reject
    }).done(function (msg) {
        feedbackMessage(msg);
    });
}

function saveQuiz(forms, quizIndex) {
    var form = forms.eq(quizIndex);
    formValid = true,
    messages = [],
    dfd = $.Deferred();
    showupdate('Updating...form ' + quizIndex);
    /*
    do a lot of client-side validation on the form here setting "valid"
   */
    if (!formValid) {
        dfd.resolve({
            success: false,
            errors: messages
        });
    } else {
        quizPost(form, dfd);
    }
    return dfd.promise();
}

saveQuiz(quizIndex).done(function (response) {
    if (response.success) {
        // saving worked; rejoice
    } else {
        // client-side validation failed
        // output the contents of response.errors
    }
}).fail(function (err) {
    // AJAX request failed
});

1 Comment

Appreciate Mark, great ref for AJAX calls in sequence.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.