Django/Js: how to post a form without reloading whole page

别等时光非礼了梦想. 提交于 2020-12-26 04:57:28

问题


My application currently flows through 3 pages:

  1. User selects question in index page
  2. User submits answer in answer page
  3. User is presented with result in results page.

I want to compress that down to a single page where the user submits an answer to the question and result is shown on the same page.

The following django-template code separates questions with Bootstrap accordion. How do I post the form without refreshing the whole page? I want to be able to display the result on the page, update CSS styling with Javascript etc.

<h2>{{ category.title }}</h2>
    <div class="accordion" id="accordion{{category.title}}">

      {% for challenge in category.challenge_set.all %} 
      <div class="card">
        <div class="card-header" id="heading{{challenge.id}}">
          <h2 class="mb-0">
            <button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapse{{challenge.id}}" aria-expanded="true" aria-controls="collapse{{challenge.id}}">
              {{ challenge.question_text }} - {{ challenge.point_value }} points
            </button>
          </h2>
        </div>
        <div id="collapse{{challenge.id}}" class="collapse in" aria-labelledby="heading{{challenge.id}}" data-parent="#accordion{{category.title}}">
          <div class="card-body">
            
            <p>{{ challenge.description }}</p>
          
            <form action="{% url 'challenges:answer' challenge.id %}" method="post">
            
              {% if challenge|is_answered:request %}
                <label for="answered">Answer</label>
                <input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
              {% else %}
              {% csrf_token %}
                <label for="answer">Answer</label>
                <input type="text" name="answer" id="answer">
                <input type="submit" value="Submit">
              {% endif %}
            </form>
        </div>
      </div>
      {% endfor %}

    </div>

Here is the view:

def index(request):
    context = {'challenges_by_category_list': Category.objects.all()}
    return render(request, 'challenges/index.html', context)

def detail(request, challenge_id):
    challenge = get_object_or_404(Challenge, pk=challenge_id)
    return render(request, 'challenges/detail.html', {'challenge': challenge})

def results(request, challenge_id, result):
    challenge = get_object_or_404(Challenge, pk=challenge_id)
    return render(request, 'challenges/results.html', {'challenge':challenge, 'result':result})

def answer(request, challenge_id):
    challenge = get_object_or_404(Challenge, pk=challenge_id)
    result = "Incorrect, try again!"
    if challenge.answer_text.lower() == request.POST['answer'].lower():
      current_user = request.user
      session = User_Challenge(user=current_user, challenge=challenge, answered=True)
      session.save()
      points = Profile(user=current_user, points=challenge.point_value)
      points.save()
      result = "Correct!"
    return HttpResponseRedirect(reverse('challenges:results', args=(challenge.id, result)))

回答1:


You can try this:

Add the below script in your template:

<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>

write a script and a function inside it to submit the form data.

<script type="text/javascript">
    function submitData( challenge_id ){
        // Get answer from the input element
        var answer = document.getElementById("answer").value;

        // add the url over here where you want to submit form & challenge_id is also taken as a parameter.
        var url = "<your_url>";

        $.ajax({
            url: url,
            data: {
                'answer': answer,
            },
            dataType: 'JSON',
            success: function(data){
                // show an alert message when form is submitted and it gets a response from the view where result is provided and if url is provided then redirect the user to that url.
                alert(data.result);
                if (data.url){
                   window.open(data.url, '_self');
                }
            }
        });
    }
</script>

Change type of the submit button and add an onclick event to call the submitData() function and pass the challenge id to it. And remove the action attr from the form. see below:

<form method="post">
    {% csrf_token %}
    {% if challenge|is_answered:request %}
        <label for="answered">Answer</label>
        <input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
    {% else %}
        <label for="answer">Answer</label>
        <input type="text" name="answer" id="answer">
        // over here
        <button type="button" onclick="submitData({{ challenge.id }})">
            Submit
        </button>
    {% endif %}
</form>

Return a JsonReponse to the ajax call from the views.

views.py

def answer(request, challenge_id):
    answer = request.GET.get('answer', False)
    url = False
    if challenge.objects.filter(id=challenge_id).exists() and answer:
       challenge = Challenge.objects.get(id=challenge_id)
       if challenge.answer_text.lower() == answer.lower():
          current_user = request.user
          session = User_Challenge(user=current_user, challenge=challenge, answered=True)
          session.save()
          points = Profile(user=current_user, points=challenge.point_value)
          points.save()
          result = "Correct!"
  
          # specify the url where you want to redirect the user after correct answer
          url = "" 
    else:
       result = "Incorrect, try again!"
    data = {
       'result': result,
       'url': url
    }
    return JsonResponse(data)


来源:https://stackoverflow.com/questions/65052844/django-js-how-to-post-a-form-without-reloading-whole-page

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!