0

I have a drop-down list and I want to let the user add a new option to it while staying on the same page. I'm trying to do it with a modal. Here's the flow:

  1. User clicks a button on the main form and a modal pops up with an "Add Reward" form
  2. User inputs data and hits submit
  3. Success --> modal closes and drop-down updates with newly added item
    Failure --> modal shows form errors like a normal form and lets user re-submit

edit_goals.html

{% load crispy_forms_tags %}

<form method="post" novalidate>
    {% crispy form %}
</form>

<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-body">
        <form method="post" id="addRewardForm" novalidate 
            data-addreward-url="{% url 'wakemeup:ajax_add_reward' %}" 
            >
            {% crispy addRewardForm %}
        </form>
      </div>
    </div>
  </div>
</div>

<script>
    $("#addRewardForm").submit(function() {
        var url = $("#addRewardForm").attr("data-addreward-url");

        $.post(
            {
                url:url,
                data: {
                    CSRF: getCSRFTokenValue()
                },
                success: function(data, status){
                    alert("Data: " + data + "\nStatus: " + status);
                }
            }
        );

        return false // Ignore original submit button
    });
</script>

views.py

def addreward(request):
    if request.method == 'POST':

        # Create form instance and bind data
        form = RewardForm(request.POST)

        if form.is_valid():

            # Create / save new reward
            myreward = Reward(
                rewardid = form.cleaned_data.get('rewardid'),
                rewardname = form.cleaned_data.get('rewardname'),
            )

            myreward.save()

            # Return nothing
            return HttpResponse('Added Successfully')

    return render(request, 'edit_form.html', {'form': form})

The problem

The callbacks are not being called. When you click submit on the modal form, it processes the new reward and saves it fine. But instead of storing the return data from the view to the data variable of the success() callback, it just shows the rendered output from the view and redirects to a different page.

What I want is to capture the rendered output to the data variable of the $.post() call so I can then display the HTML inside the modal as I please.

I tried converting $.post() to $.ajax() and including the error callback, but nothing. The success callback doesn't even return a simple alert() either.

I am doing similar processing with GET requests and the callback works fine there. What am I missing here?

halfer
  • 19,824
  • 17
  • 99
  • 186
ravioli
  • 3,749
  • 3
  • 14
  • 28

2 Answers2

1

Within your html file after declaring the form.submit, you should pass the

$("#addRewardForm").submit(function(e) // <== Add this (e) {
   e.preventDefault(); // <== Add this

So that when the form is submitted, it fires the result before reloading.

Luay
  • 789
  • 4
  • 15
  • Thanks for the tip. This will help me later on. It turns out my "hack-away until you get it to work" technique tripped me up. I had copy-pasted the line `CSRF: getCSRFTokenValue()` from some other post and the function was never defined. – ravioli Jul 16 '18 at 02:24
  • @ravioli Happens to the best of us! Happy that you found out where the problem is, those sometimes eat an entire day! Good Luck! – Luay Jul 16 '18 at 02:25
  • Hah, no kidding :) Thanks again. – ravioli Jul 16 '18 at 02:26
0

(Posted solution on behalf of the question author).

It turns out CSRF: getCSRFTokenValue() was never defined anywhere else, causing the JavaScript to fail. I replaced it with the csrfmiddlewaretoken suggestion from this post:

Jquery and Django CSRF Token

halfer
  • 19,824
  • 17
  • 99
  • 186