views:

44

answers:

2

During early in learning how to implement unobtrusive js (using Rails & jQuery) I've run into an issue of how to (re)bind a submit button/form after .load(ing) new content that includes a form.

I've set up a 'create new item' form to show at the top of a lising of items (when the user clicks on a create button)

sale_case/show/_requirments_new.html.haml:

- form_for ([@sale_case, @sale_case_requirement]), :html => { :id => 'requirement_form', :class => "submit-with-ajax"} do |f|
...
%button{ :type => "submit" } Save Requirement

application.js:

jQuery(document).ready(function() {
  jQuery(".submit-with-ajax").submitWithAjax();
}
...
jQuery.ajaxSetup({
  'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})

jQuery.fn.submitWithAjax = function() {
  this.submit(function() {
    jQuery.post(this.action, jQuery(this).serialize(), null, "script");
    return false;
  })
  return this;
};

requirements_controller.rb:

def create
  @sale_case_requirement = @sale_case.requirements.new(params[:requirement])
      if @sale_case_requirement.save
      @message = "Success..."
      @success = true
  #...
  respond_to do |format|
    format.js
  end
end

requirements/create.js.erb:

mesg("<%= @message %>");
<%- if @success %>
  jQuery("#requirement_form")[0].reset();
  jQuery('#requirements').load('<%= requirements_view_sale_case_requirements_path(@sale_case.id) %>' );
<% end %>

It's all working well the first time around unobtrusively. The problem comes when the user creates the second item (on the form loaded via ajax). The button is not getting bound to the submitWithAjax function. How do you do that when .load(ing) content?

I ended up having to do this in the partial (obtrusive) in order to get it to work, but it bugs me not to be able to figure this out. :

%button{ :type => "submit", :onclick => "jQuery.post('#{sale_case_requirements_path(@sale_case.id, @sale_case_requirement.id)}', jQuery('#requirement_form').serialize(), null, 'script'); return false;"} Save Requirement
+1  A: 

Change this original code:

jQuery(document).ready(function() {
  jQuery(".submit-with-ajax").submitWithAjax();
}

to this:

jQuery(document).ready(function() {
  jQuery(".submit-with-ajax").live('submit', submitWithAjax);
}

and this original code:

jQuery.fn.submitWithAjax = function() {
  this.submit(function() {
    jQuery.post(this.action, jQuery(this).serialize(), null, "script");
    return false;
  })
  return this;
};

to this:

jQuery.fn.submitWithAjax = function() {
    jQuery.post(this.action, jQuery(this).serialize(), null, "script");
    return false;
};

The jQuery .live() call binds the named handler to the named event on all current and future elements that match the given selector, including elements that are loaded in via ajax. Hopefully that does what you're looking for.

See the following for documentation on the .live() function: http://api.jquery.com/live/

Ender
Awesome. Thanks so much for your time. (I've benefitted so much from Stack Overflow recently I'm trying to engage and help give back.) See my answer for an issue I had and what I finally did.
Robert Pierce
+1  A: 

Here's what I ended up changing in the code based on Ender's input. I got an error with finding 'submitWithAjax' with his version of the code, but he pointed me in the right direction and after reading the .live documentation I came up with this which works:

application.js

jQuery(document).ready(function() {

  # Just put it all in one place
  jQuery(".submit-with-ajax").live('submit', function() {
        jQuery.post(this.action, jQuery(this).serialize(), null, "script");
        return false;
      });
...
}

sale_case/show/_requirments_new.html.haml:

# Change the button back to unobtrusive
%button{ :type => "submit"} Save Requirement    

Thanks!

Robert Pierce
Yeah, upon review, I'm pretty sure that having the parens after the function name in the .live() call was causing the error you came up with.
Ender