1

I am dynamically trying to pass data that I get from my for loop to the buttons. I am using django to get the data in the for loop, html to make the button and jquery to pass the data. I am not sure if this is the best description though.

My code is:

{% for dogs in Dogs.Other %}
    <form id="primaryDogForm" action="{% url 'personal:account:email_dog_confirm' %}" method="post">
        {% csrf_token %}
        <input type="hidden" id="dogId" name="dogId" value="{{ dogs }}">
        <input type="button" value="Make this your primary dog" id="makePrimaryButton" class="btn btn-primary" data-toggle="modal" data-target="#makePrimary" />
    </form>
{% endfor %}

Basically, people can add a list of dogs to their account and select a dog to be their primary dog. I want a modal to be called when I click on the button. And that modal should display the name of the dog that is potentially being made the primary dog. The modal code is as follows:

<div class="modal fade" id="makePrimary" tabindex="-1" role="dialog" aria-hidden="true">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                    <h4 class="modal-title">Make Primary</h4>
                </div>
                <div class="modal-body">
                    <p>
                            You are about to make <span id="newDog" name="newDog"></span> your primary dog.
                        </p>
                        <hr>
                    <a href="#" id="makePrimarySubmit" class="btn btn-primary">Submit</a>
                </div>
            </div>
        </div>
    </div>

The jquery for to make everything work is:

$('#makePrimaryButton').click(function() {
            ($('#newDog').text($('#dogId').val()));
 });

$('#makePrimarySubmit').click(function(){
            $('#primaryDogForm').submit();
});

The problem I am facing is that, suppose I have a list of three dogs, each with a "Make this your primary dog" button, then the button works for only the first dog. The rest of buttons dont work until the first button gets clicked. Once the first button is clicked, all the other buttons also get the value of the first dog. Hence, the dog 2 and dog 3 in the list cant be made primary dogs.

I am pretty sure the problem is with my html and jquery. Is there a way for me to make button dynamic so that the button gets the value of the dog it is associated with? That way, any dog can be made primary dog.

Thank you so much.

2 Answers2

3

The problem here is with the ID's you're placing on the initial HTML in the for loop. ID's are unique in HTML - you should only have one of them with that ID name on a page. This is also why the jquery selector only picks up the first button properly.

Instead, one way to fix this is to use classes instead of ID's, like so:

{% for dogs in Dogs.Other %}
  <form class="primaryDogForm" action="{% url 'personal:account:email_dog_confirm' %}" method="post">
      {% csrf_token %}
      <input type="hidden" class="dogId" name="dogId" value="{{ dogs }}">
      <input type="button" value="Make this your primary dog" class="btn btn-primary makePrimaryButton" data-toggle="modal" data-target="#makePrimary" />
  </form>
{% endfor %}

Then you'll need to update your jquery code to reflect this change:

var lastEditedForm = null;

$('.makePrimaryButton').click(function() {
  lastEditedForm = $(this).closest('form');
  var dogId = lastEditedForm.find('.dogId').val();
  $('#newDog').text(dogId);
});

$('#makePrimarySubmit').click(function(){
  lastEditedForm.submit();
});

Note that because you've got a click event for the modal defined outside of which dog button you've clicked - which dog button got clicked last needs to be tracked for when the modal is confirmed.

Using a variable outside the two click handlers is just one way to deal with this, and potentially not the best way. Another approach is to define a temporary event handler after the initial dog button is clicked - but that also requires ensuring that the event gets cleaned up properly in the event the modal gets cancelled.

-- Edit explaining temporary event handler --

In order to have a temporary event handler created on each of your dog button clicks, you also need to ensure that the temporary handler gets removed (no matter what) each time. In this case, because you're using a bootstrap modal, we can use the close event on the modal to definitively clear out the event handler.

The javascript looks like this:

$('.makePrimaryButton').click(function() {
  // note we're still placing the form in a variable here
  // so we have easy reference to it in the temporary event
  // handler below
  var currentForm = $(this).closest('form');
  var dogId = currentForm.find('.dogId').val();
  $('#newDog').text(dogId);

  $('#makePrimaryButton').one('click', function(){
    currentForm.submit();
  })
});

// hidden.bs.modal is for Bootstrap v3 or v4. If you're using
// Bootstrap v2 it's just 'hidden.'
$('#makePrimary').on('hidden.bs.modal', function(){
  // clears absolutely all event handlers on the button,
  // not just the ones we set. We would need a reference to
  // the function we set earlier in order to take just
  // that function off.
  $('#makePrimaryButton').off();
})
Mike
  • 123
  • 5
  • Thank you so much for your answer. Could you please elaborate on how I can accomplish "Another approach is to define a temporary event handler after the initial dog button is clicked - but that also requires ensuring that the event gets cleaned up properly in the event the modal gets cancelled." – Deeksha Juneja Jun 02 '17 at 19:18
  • @DeekshaJuneja I updated my answer with details on a temporary event handler. Note the event handler placed at the bottom, which takes action once the modal is done (whether submitted or cancelled). That ensures the event handler has been removed regardless what option the user chooses. – Mike Jun 02 '17 at 19:37
  • So basically with that, I wont need to use `$('#makePrimarySubmit').click(function(){ $('#primaryDogForm').submit(); });` ? However, wont this associate my submitting to the makePrimaryButton, when I am trying to hold off the submit until the user clicks on the makePrimarySubmit? – Deeksha Juneja Jun 02 '17 at 19:48
  • @DeekshaJuneja correct, you won't need the snippet you put in your comment anymore. My example works how you desire because once you click on a Dog button to bring up the form, at that moment it sets a handler on the #makePrimarySubmit button, so that the Dog form the user clicked on will have .submit() called on it after #makePrimarySubmit is clicked. This will only submit the Dog form once the modal submit button is clicked. Does that clear it up at all? – Mike Jun 02 '17 at 19:59
  • Ya, that does make sense. However, I did try doing it and it makes my Submit button in the modal not do anything. So basically, the submit action doesnt work. So instead I just used `$('.makePrimarySubmit').click(function(){ lastEditedForm.submit(); });` as per your easier suggestion and that seems to do the trick. Thank you so much for the help!!! – Deeksha Juneja Jun 02 '17 at 20:15
0

You should add a data attribute to the button. The link below gives a good example of it's implementation:

Passing data to a bootstrap modal

Simon
  • 764
  • 4
  • 8