Modal unbind on fade

2019-08-28 23:41发布

问题:

This is version of a previously asked question (Modal windows and binding/unbinding).

I have a form and when "Add New" is selected a modal window appears in which text can be typed in a field to add to the dropdown. This can happen for 8 or 9 fields. The bug is that if the user dismisses the modal by clicking either on the "X" or on the dark space around the box and then selected "Add New" again and clicks the "Add" button, the modal is still bound to the event (I guess) and so there is a double entry and the modal is never dismissed and one has to reload the page and start over.

So how do I unbind the modal when it's dismissed either with the "X" or by clicking outside the box? I've tried everything I can think of under the sun (a few examples are commented out below). I've tried unnesting the clicks as suggested here Why does jQuery ajax post twice here? but that doesn't work, or I don't know how to implement it correctly. Been at this a while. Any thoughts?

<div class="container">
<div class="row">
   <div class="span12">   

       <h3>Upload your experimental data</h3>
       <form class="form-horizontal well" action="<?php echo site_url(); ?>main/upload_data" method="post" enctype="multipart/form-data" id="upload_form">

                <fieldset>
                  <legend>Animal Info</legend>

                    <!-- Animal Species -->
                    <div class="control-group <?php if (form_error('animal_species')) { echo 'error'; } ?>">
                        <label class="control-label">Species</label>            
                        <div class="controls">

                            <?php

                            # Add "Add New"
                            $options = $species + array('addnew' => 'Add New'); 
                            //var_dump($options);
                            echo form_dropdown('animal_species', $options
                                                , set_value('animal_species', (isset($my_data->animal_species)) ? $my_data->animal_species: '')
                                                , 'id = "animal_species"'
                                                , 'class="animal_species"', 'addnew'
                                                );
                            echo form_error('animal_species', '<span class="help-inline">', '</span>');                                
                            # var_dump($options);

                            //unset($species[0]); // remove first (blank) element
                            //$options_keys = $species;
                            //var_dump($options_keys);

                            ?> 

                        </div>
                    </div>                            


                    <!-- Animal Condition -->
                    <div class="control-group <?php if (form_error('animal_condition')) { echo 'error'; } ?>">
                        <label class="control-label">Animal Condition</label>            
                        <div class="controls">

                            <?php
                            # Add "Add New"
                            $options = $condition + array('addnew' => 'Add New'); 
                            //var_dump($options);
                            echo form_dropdown('animal_condition', $options
                                                , set_value('animal_condition', (isset($my_data->animal_condition)) ? $my_data->animal_condition: '')
                                                , 'id = "animal_condition"'
                                                , 'class="animal_condition"', 'addnew'
                                                );
                            echo form_error('animal_condition', '<span class="help-inline">', '</span>');                                
                            ?> 

                        </div>
                    </div>                            

                    <!-- Brain Area -->
                    <div class="control-group <?php if (form_error('brain_area')) { echo 'error'; } ?>">
                        <label class="control-label">Brain Region</label>            
                        <div class="controls">

                            <?php
                            # Add "Add New"
                            $options = $area + array('addnew' => 'Add New'); 
                            //var_dump($options);
                            echo form_dropdown('brain_area', $options
                                                , set_value('brain_area', (isset($my_data->brain_area)) ? $my_data->brain_area: '')
                                                , 'id = "brain_area"'
                                                , 'class="brain_area"', 'addnew'
                                                );
                            echo form_error('brain_area', '<span class="help-inline">', '</span>');                                
                            ?> 

                        </div>
                    </div>                            

                </fieldset>

                <!-- submit -->
                <div class="form-actions">
                    <button type="submit" class="btn btn-primary">Upload &raquo;</button>
                </div>
       </form>
  </div>
  </div><!-- end row -->

  <script type="text/javascript">

  var Classofentry = '';

        $('#upload_form option[value="addnew"]').click(function(event){

          var Classofentry = $(this).attr("class");

          $('#add-new-text').val(''); // Set input text field to blank

          // Show modal window
          $('#add-new').modal('show');

          $('#add-new-submit').click(function(){

              var value = $('#add-new-text').val();

              $.ajax({
                    type: "POST",
                    url: "<?php echo site_url(); ?>main/change_options",
                    data: {new_option: value, new_option_class: Classofentry},
                    //dataType: "html",
                    dataType: "json",
                    error: errorHandler,
                    success: success
                  });

              function success(data)
              {
                  if (data[1])
                  {
                    // Add new entry
                    $('#'+Classofentry).append("<option value='" + data[0] + "'selected=\"selected\">" + data[0] + "</option>");
                    //alert(data[1]);
                  }
                  else
                  { 
                    // Select the nonunique value by emptying it and appending
                    $('#'+Classofentry).empty("<option value=''selected=\"selected\">" + data[0] + "</option>").append("<option value='" + data[0] + "'selected=\"selected\">" + data[0] + "</option>");                                                          
                    //alert(data[0]);                             
                  }

              }

              function errorHandler()
              {
                  //alert('Error with AJAX!');
                  alert(data[0]);
              } 

              $('#add-new-submit').unbind('click'); // This fixes the problem for multiple entries
              $('#add-new').modal('hide');

          });

        });


  </script>

  <!-- add-new field -->
  <div class="modal small hide fade" id="add-new" tabindex="-1" role="dialog" aria-labelledby="add-new-fieldLabel" aria-hidden="true">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
        <h3 id="add-new-fieldLabel">Add New Field</h3>
      </div>
      <div id="modal-body" class="modal-body">

          <p>Would you like to add a new <span1></span1> option?</p>
          <input type="text" id="add-new-text" name="add-new-text" placeholder="Type the new option">

      </div>

      <div class="modal-footer">
        <button type="button" class="btn btn-success" id="add-new-submit" name="add-new-submit"/>Add</button>
      </div>
 </div><!-- /add-new field -->

I've edited to include more code now. It's all in one view, but I've included the top part of the form now. The problem is that when Add New is selected at

$('#upload_form option[value="addnew"]').click(function(event){ 

it is bound to all future clicks at

$('#add-new-submit').click(function(){ 

so that if the user selects Add New and then dismisses the modal window by clicking off of it, it is still bound and when Add New is selected again and text is actually entered and the Add button is clicked that text gets entered in both that field and the previous field.

So my question still stands: how do I unbind the click event

$('#upload_form option[value="addnew"]').click(function(event){ 

when the modal is dismissed by clicking the x or clicking off the window?

I've been told not to nest clicks, but I don't know how to do this without nesting clicks since the first click event brings up the second click event (although the second one is an Add button and so I suppose doesn't have to be a click; but I haven't been able to get it to work as a submit).

Help!

回答1:

First of all, i allowed myself to remove all PHP stuff from your HTML since it's not important for this.

<div class="container">
  <div class="row">
    <div class="span12">   

      <h3>Upload your experimental data</h3>
      <form class="form-horizontal well" action="/" method="post" enctype="multipart/form-data" id="upload_form">

        <fieldset>
          <legend>Animal Info</legend>

          <!-- Animal Species -->
          <div class="control-group">
            <label class="control-label">Species</label>            
            <div class="controls">
              <select>
                <option>&lt;choose&gt;</option>
                <option value="addnew">Add new</option>
              </select>
            </div>
          </div>

          <!-- Animal Condition -->
          <div class="control-group">
            <label class="control-label">Animal Condition</label>            
            <div class="controls">
              <select>
                <option>&lt;choose&gt;</option>
                <option value="addnew">Add new</option>
              </select>
            </div>
          </div> 

          <!-- Brain Area -->
          <div class="control-group">
            <label class="control-label">Brain Area</label>            
            <div class="controls">
              <select>
                <option>&lt;choose&gt;</option>
                <option value="addnew">Add new</option>
              </select>
            </div>
          </div> 

        </fieldset>

        <!-- submit -->
        <div class="form-actions">
          <button type="submit" class="btn btn-primary">Upload &raquo;</button>
        </div>

      </form>
    </div>
  </div><!-- end row -->

  <!-- add-new field -->
  <div class="modal small hide fade" id="add-new" tabindex="-1" role="dialog" aria-labelledby="add-new-fieldLabel" aria-hidden="true">
    <div class="modal-header">
      <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
      <h3 id="add-new-fieldLabel">Add New Field</h3>
    </div>

    <div id="modal-body" class="modal-body">
      <p>Would you like to add a new <!-- wtf? <span1></span1> --> option?</p>
        <input type="text" id="add-new-text" name="add-new-text" placeholder="Type the new option" />
    </div>

    <div class="modal-footer">
      <button type="button" class="btn btn-success" id="add-new-submit" name="add-new-submit">Add</button>
    </div>
  </div><!-- /add-new field -->
</div>

.

And i also refacrtored your javascript code, i annotated all important changes, i hope it's not to confusing (I also removed the actual ajax call since it's unnecessary to show up what's happening)

$('#upload_form select').change(function(event){
  var $select = $(this);
  // abort if selected option is not the addnew one
  if ($select.val() !== 'addnew') return;

  // Get all elements we'll need later on once and put them in a variable,
  // so jquery don't has to search them all over again everytime we need them
  // http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-jquery-newbs-stop-jumping-in-the-pool/
  var $add_new        = $('#add-new')
    , $add_new_text   = $('#add-new-text')
    , $add_new_submit = $('#add-new-submit')
    , addNewOption; // This variable will get assigned our click handler, we'll need this later on

  // Show the modal
  $add_new.modal('show');

  // You want this event handle to get called only once, .one() will do exactly that
  // http://api.jquery.com/one/
  $add_new_submit.one('click', addNewOption = function() { // Like i said above
    var new_option_value = $add_new_text.val()

      // Create a new option element
      , $new_option = $('<option/>');

    // Set it's value and text to the user input
    // Note: in your application you should escape this before using it in any way, never trust user input
    $new_option.val(new_option_value).text(new_option_value);

    // Assuming the "Add New" option should always be the last one,
    // add the new option in before it.
    $select.children().last().before($new_option);

    // Select it
    $new_option.prop('selected', true);

    $add_new_text.val('');
    $add_new.modal('hide');
  });

I think this is what will solve your actual problem: Bootstrap Modals will trigger a event when they'll hide (as well as when they will show up) source

Note: In case you're already using Bootstrap 3, the you'll have to change the event name to hide.bs.modalsource

  $add_new.one('hide', function () {
    // This will unbind explicitly the handler we attached above
    $add_new_submit.unbind('click', addNewOption); 
  });
});

Here you can find a functional jsFiddle with this code.

Hope i could help you on this, if you have any questions, feel free to ask :)