0

I recently asked this question: Javascript Form Submition?

Now I'm trying to work out why, after form submission, the create.js.erb doesn't load the latest data (the data which was submitted).

If I submit the data again, the table will update with the second last data but not the absolute latest.

...why?

EDIT:

Latest code -

Categories controller: class Admin::CategoriesController < Admin::AdminController ...

  def create
    @category = Admin::Category.new(params[:admin_category])
    # You can't retrieve the @categories before attempting to add new one. Keep at end of create method.
    @categories = Admin::Category.all
    respond_to do |format|
      if @category.save
        save_to_history("The category \"#{@category.name}\" has been created", current_user.id)
        format.json { render json: { html: render_to_string(partial: 'categories') } }
        # I've tried both the above and bellow
        #format.json { render json: { html: render_to_string('categories') } }
        format.html { redirect_to(admin_categories_url, :notice => 'Category was successfully created.') }
        format.xml  { render :xml => @category, :status => :created, :location => @category }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @category.errors, :status => :unprocessable_entity }
      end
    end

  end

  ...
end

Javascript:

<script type='text/javascript'>
  $(function(){
    $('#new_admin_category').on('ajax:success', function(event, data, status, xhr){
      $("#dashboard_categories").html(data.html);
    });
  });
</script>

SOLVED

I used @PinnyM's method and added a create.json.erb file with the following code:

<% self.formats = ["html"] %>
{
  "html":"<%= raw escape_javascript( render :partial => 'categories', :content_type => 'text/html') %>"
}

and changed my create method to:

def create
    @category = Admin::Category.new(params[:admin_category])

    respond_to do |format|
      if @category.save
        # You can't retrieve the @categories before attempting to add new one. Keep after save.
        @categories = Admin::Category.all
        save_to_history("The category \"#{@category.name}\" has been created", current_user.id)
        format.json 
        format.html { redirect_to(admin_categories_url, :notice => 'Category was successfully created.') }
        format.xml  { render :xml => @category, :status => :created, :location => @category }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @category.errors, :status => :unprocessable_entity }
      end
    end
  end

Please do offer suggestions if this is messy.

Community
  • 1
  • 1
Taylor Williams
  • 256
  • 4
  • 22

3 Answers3

1

You need to handle the success callback for your remote (AJAX) submission. The data parameter (2nd argument) holds the response:

$(function(){
  $('#new_category').on('ajax:success', function(event, data, status, xhr){
    eval(data);
  });
});

A better way to do this (and avoid the dangerous eval) might be to just return the partial, and have the callback decide what to do with it:

# in create action
format.json { render json: { html: render_to_string('categories') } }

# in your js, run at page load
$(function(){
  $('#new_category').on('ajax:success', function(event, data, status, xhr){
    $("#dashboard_categories").html(data.html);
  });
});

UPDATE

Just noticed what @RomanSpiridonov wrote - he's absolutely correct. You can't retrieve the @categories before attempting to add your new one. Move the line @categories = ... to the end of the create method.

Also, I noticed that your Category model is namespaced - that means your default form id attribute is more likely something like 'new_admin_category'. You should check how it is actually being rendered and use that id in your jQuery selector when registering the success callback:

$(function(){
  $('#new_admin_category').on('ajax:success', function(...
PinnyM
  • 35,165
  • 3
  • 73
  • 81
  • Are you serious? `eval` in an answer to a question, tagged _**unobtrusive JavaScript**_, and assuming jQ when there is no jQ tag? – Elias Van Ootegem May 13 '13 at 14:38
  • @EliasVanOotegem: was getting to that. Without `eval` there's no way to have the browser parse the javascript being passed back, which is why I suggest not passing back any javascript. Regarding jQ - in the linked question, the accepted answer was to use `jquery_ujs` - which requires the use of jQuery. – PinnyM May 13 '13 at 14:41
  • Yup, trying to spot the JS in the linked code, I noticed jQ, too. Though I'd hardly classify the OP's intentions as fitting the _unobtrusive JS_ tag... Perhaps best retag this question :) – Elias Van Ootegem May 13 '13 at 14:45
  • Sorry about the confusion. So how do I implement this? I've just tried - but maybe I'm missing something? Sorry - you're going to have to hold my hand here, I'm a novice! – Taylor Williams May 13 '13 at 14:53
  • @TaylorWilliams: change your action to use `format.json` instead of `format.js`, register the 'ajax:success' callback in your categories.js file or anywhere on the page (to run after the page loads using `$(function(){...})`), and you can remove the unneeded `create.json.erb`. If this isn't working for you, perhaps post your revised code - and please post it inline (pastie is great, but not reliable for SO). – PinnyM May 13 '13 at 14:59
  • Thank you so much guys for your contribution! I'm now getting this 'Missing template admin/categories/categories, admin/admin/categories, application/categories with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder, :coffee]}.'. I've tried editing the json render_to_String to '_categories' and 'categories.html.erb' - no prevail. Something I am missing? – Taylor Williams May 14 '13 at 08:36
1

Instance variable @categories in method "create" defined before saving new category. That's why you can't receive the lastest category in your template. I think you could write something like that:

$("#dashboard_categories").append("<%= escape_javascript(render("category")) %>");

expellee
  • 21
  • 2
0

You could add this piece of javascript in a file inside assets/javascripts folder

$(your_form_selector).on('ajax:success', function(){
  // Read link to see what event names you can use instead of ajax:success and
  // which arguments this function provides you.
})

To set your_form_selector you could add an id to your form and use #myFormId

Read more here

sites
  • 21,417
  • 17
  • 87
  • 146