admin管理员组

文章数量:1420907

** UPDATE ** I changed the HTML id's to classes. And incorporated the advice in the current top answer. The autoplete now works but the autoplete option list DOES NOT successfully display for the dynamically adde text input field. It works for the original though.

I have added the updated code below.

I just added jQuery UI autoplete to a form in my Rails app. The feature works fine however it doesn't work when I dynamically add another input field with the same class?

<a href="#" class="addNewIngredient">Add ingredient</a>

After dynamically adding an additional field, the original field's autoplete feature continues to work without any issues but the newly added field's autoplete feature does not work.

Why would the autoplete feature fail for the dynamically added field if the input fields all share the same id?

application.js

$(document).ready(function(){
$(".addNewIngredient").on('click', function(e){
  e.preventDefault();
$(".ingredientField").append($("#new_ingredients_form").html());
$(".select_ingredient").autoplete({
        minLength: 2,
        source: '/ingredients',
        focus: function(event, ui) {
            $('.select_ingredient').val(ui.item.name);
            return false;
        },
        select: function(event, ui) {
            $('.select_ingredient').val(ui.item.name);
    $('.link_ingredient_id').val(ui.item.id);
            return false;
        }
    })
    .data( "ui-autoplete" )._renderItem = function( ul, item ) {
        return $( "<li></li>" )
            .data( "ui-autoplete-item", item )
            .append( "<a>" + item.name + "</a>" )
            .appendTo( ul );
    };
});

$(".removeIngredient").on('click', function(e){
  e.preventDefault();
$(".ingredientField #new_ingredients_form").empty();
});
});

new.html.erb

<h1>Create Meal</h1>
<%= form_for(@meal) do |f| %>

  <%= f.label :name %>
  <%= f.text_field :name %><br/>

  <div class="ingredientField">
    <%= render "ingredient_form" %>
  </div>
  <a href="#" class="addNewIngredient">Add ingredient</a>
  <a href="#" class="removeIngredient">Remove ingredient</a>

  <%= f.label :clean_up %>
  <%= f.select :clean_up, options_for_select([["", ""],["Low", "low"], ["Med", "med"], ["High", "high"]]) %><br/>

  <%= f.label :homemade %>
  <%= f.select :homemade, options_for_select([["Yes", true],["No", false]])  %><br/>

  <%= f.submit "Save" %>
<% end %>

_ingredient_form.html.erb

    <script type="text/javascript">
    $(function() {
 // Below is the name of the textfield that will be autoplete
    $('.select_ingredient').autoplete({
 // This shows the min length of charcters that must be typed before the autoplete looks for a match.
            minLength: 2,
 // This is the source of the auoplete suggestions. In this case a list of names from the people controller, in JSON format.
            source: '<%= ingredients_path(:json) %>',
  // This updates the textfield when you move the updown the suggestions list, with your keyboard. In our case it will reflect the same value that you see in the suggestions which is the person.given_name.
            focus: function(event, ui) {
                $('.select_ingredient').val(ui.item.name);
                return false;
            },
 // Once a value in the drop down list is selected, do the following:
            select: function(event, ui) {
 // place the person.given_name value into the textfield called 'select_origin'...
                $('.select_ingredient').val(ui.item.name);
 // and place the person.id into the hidden textfield called 'link_origin_id'.
        $('.link_ingredient_id').val(ui.item.id);
                return false;
            }
        })
 // The below code is straight from the jQuery example. It formats what data is displayed in the dropdown box, and can be customized.
        .data( "ui-autoplete" )._renderItem = function( ul, item ) {
            return $( "<li></li>" )
                .data( "item.autoplete", item )
 // For now which just want to show the person.name in the list.
                .append( "<a>" + item.name + "</a>" )
                .appendTo( ul );
        };
    });
    </script>


<div class="ingredientsForm" id="new_ingredients_form">
  <%= label_tag "ingredients" %>
  <input class="select_ingredient"/>
  <input class="link_ingredient_id" name="link[ingredient_id]" type="hidden"/>
  <%= label_tag "servings" %>
  <%= text_field_tag "servings[]" %>
</div>

ingredients_controller.rb

class IngredientsController < ApplicationController
  before_filter :authenticate_user!

  def index
    if params[:term]
      @ingredients = Ingredient.find(:all,:conditions => ['name LIKE ?', "#{params[:term]}%"])
    else
      @ingredients = Ingredient.all
    end

    respond_to do |format|
      format.html
      format.json { render :json => @ingredients.to_json }
    end
  end
end

** UPDATE ** I changed the HTML id's to classes. And incorporated the advice in the current top answer. The autoplete now works but the autoplete option list DOES NOT successfully display for the dynamically adde text input field. It works for the original though.

I have added the updated code below.

I just added jQuery UI autoplete to a form in my Rails app. The feature works fine however it doesn't work when I dynamically add another input field with the same class?

<a href="#" class="addNewIngredient">Add ingredient</a>

After dynamically adding an additional field, the original field's autoplete feature continues to work without any issues but the newly added field's autoplete feature does not work.

Why would the autoplete feature fail for the dynamically added field if the input fields all share the same id?

application.js

$(document).ready(function(){
$(".addNewIngredient").on('click', function(e){
  e.preventDefault();
$(".ingredientField").append($("#new_ingredients_form").html());
$(".select_ingredient").autoplete({
        minLength: 2,
        source: '/ingredients',
        focus: function(event, ui) {
            $('.select_ingredient').val(ui.item.name);
            return false;
        },
        select: function(event, ui) {
            $('.select_ingredient').val(ui.item.name);
    $('.link_ingredient_id').val(ui.item.id);
            return false;
        }
    })
    .data( "ui-autoplete" )._renderItem = function( ul, item ) {
        return $( "<li></li>" )
            .data( "ui-autoplete-item", item )
            .append( "<a>" + item.name + "</a>" )
            .appendTo( ul );
    };
});

$(".removeIngredient").on('click', function(e){
  e.preventDefault();
$(".ingredientField #new_ingredients_form").empty();
});
});

new.html.erb

<h1>Create Meal</h1>
<%= form_for(@meal) do |f| %>

  <%= f.label :name %>
  <%= f.text_field :name %><br/>

  <div class="ingredientField">
    <%= render "ingredient_form" %>
  </div>
  <a href="#" class="addNewIngredient">Add ingredient</a>
  <a href="#" class="removeIngredient">Remove ingredient</a>

  <%= f.label :clean_up %>
  <%= f.select :clean_up, options_for_select([["", ""],["Low", "low"], ["Med", "med"], ["High", "high"]]) %><br/>

  <%= f.label :homemade %>
  <%= f.select :homemade, options_for_select([["Yes", true],["No", false]])  %><br/>

  <%= f.submit "Save" %>
<% end %>

_ingredient_form.html.erb

    <script type="text/javascript">
    $(function() {
 // Below is the name of the textfield that will be autoplete
    $('.select_ingredient').autoplete({
 // This shows the min length of charcters that must be typed before the autoplete looks for a match.
            minLength: 2,
 // This is the source of the auoplete suggestions. In this case a list of names from the people controller, in JSON format.
            source: '<%= ingredients_path(:json) %>',
  // This updates the textfield when you move the updown the suggestions list, with your keyboard. In our case it will reflect the same value that you see in the suggestions which is the person.given_name.
            focus: function(event, ui) {
                $('.select_ingredient').val(ui.item.name);
                return false;
            },
 // Once a value in the drop down list is selected, do the following:
            select: function(event, ui) {
 // place the person.given_name value into the textfield called 'select_origin'...
                $('.select_ingredient').val(ui.item.name);
 // and place the person.id into the hidden textfield called 'link_origin_id'.
        $('.link_ingredient_id').val(ui.item.id);
                return false;
            }
        })
 // The below code is straight from the jQuery example. It formats what data is displayed in the dropdown box, and can be customized.
        .data( "ui-autoplete" )._renderItem = function( ul, item ) {
            return $( "<li></li>" )
                .data( "item.autoplete", item )
 // For now which just want to show the person.name in the list.
                .append( "<a>" + item.name + "</a>" )
                .appendTo( ul );
        };
    });
    </script>


<div class="ingredientsForm" id="new_ingredients_form">
  <%= label_tag "ingredients" %>
  <input class="select_ingredient"/>
  <input class="link_ingredient_id" name="link[ingredient_id]" type="hidden"/>
  <%= label_tag "servings" %>
  <%= text_field_tag "servings[]" %>
</div>

ingredients_controller.rb

class IngredientsController < ApplicationController
  before_filter :authenticate_user!

  def index
    if params[:term]
      @ingredients = Ingredient.find(:all,:conditions => ['name LIKE ?', "#{params[:term]}%"])
    else
      @ingredients = Ingredient.all
    end

    respond_to do |format|
      format.html
      format.json { render :json => @ingredients.to_json }
    end
  end
end
Share Improve this question edited Jul 13, 2014 at 22:29 Smooth asked Jul 13, 2014 at 3:53 SmoothSmooth 9561 gold badge15 silver badges39 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

Fixed it by using $(document).on("keydown.autoplete",".select_ingredient",function(e){}

Fully revised function:

<script type="text/javascript">
$(function() {
$(document).on("keydown.autoplete",".select_ingredient",function(e){
$(this).autoplete({
         minLength: 2,
        source: '<%= ingredients_path(:json) %>',
        focus: function(event, ui) {
            $(this).val(ui.item.name);
            return false;
        },
         select: function(event, ui) {
             $(this).val(ui.item.name);
     $('.link_ingredient_id').val(ui.item.id);
            return false;
        }
    })
     .data( "ui-autoplete" )._renderItem = function( ul, item ) {
        return $( "<li></li>" )
            .data( "item.autoplete", item )
             .append( "<a>" + item.name + "</a>" )
            .appendTo( ul );
    };
  });
});
</script>

Try using this:

$(document).ready(function(){
$("#addNewIngredient").on('click', function(){
  e.preventDefault();
$("#ingredientField").append($("#new_ingredients_form").html());
});

$("#removeIngredient").on('click', function(){
  e.preventDefault();
$("#ingredientField #new_ingredients_form").empty();
});
});

See the first answer here.

Other thing you can do is: write your jquery code in a function(say applyJquery() ) and write href="#" onclick="applyJquery(); or href="javascript:applyJquery();

Jquery often does not works with dynamically created elements the way it works with static ones.

Use .on() see example here

EDIT: write: $(document).on("event",".class",function(e){ $(this).autoplete({ //write something });

It should be

$('form').on('click', '#addNewIngredient', function() {...

however duplicate ID's are invalid html, so you should use a classname instead of the id attribute e.g.

<a href="javascript:;" class="addNewIngredient">Add ingredient</a>

and

$('form').on('click', '.addNewIngredient', function() {...

本文标签: javascriptjQuery autocomplete failing after dynamically adding additional text input fieldStack Overflow