Updating various DOM elements after best_in_place

2019-04-02 10:58发布

问题:

I have various values in a table that need to be updated after a DOM element is updated using best_in_place. How can you trigger a javascript action like "create.js.erb" called "update.js.erb" after a best in place update?

For example, I have a table of item prices, and I need the table's "total" field to update after a user updates an individual item quantity.

回答1:

I've seen many people asking this question, but haven't found a satisfactory solution. I found the best approach is to create a javascript function that watches for a particular DOM element to update after an ajax:success, and then use jQuery to update a specified DOM element.

In the controller of the item being updated, I package a JSON response that includes all of the information my javascript will need in order to update DOM elements.

You'll see I also render the new table row's partial as an HTML string, and pass this string along with the JSON response.

___Item Controller_____

    respond_to do |format|
  if @item.update_attributes(params[:item])

    #json response variables to refresh table row after update
    id = [@item]  
    new_row = render_to_string('items/_item.html', :layout => false, :locals => { :item => @item })
    #----------json-variables-----------#

    format.json { render :json => { new_row: new_row, id: id, :status => 200 }}
    format.js   
  else
    format.json { render :json => @item.errors.full_messages, :status => :unprocessable_entity }
    format.js
  end
end

Then in a .js file that gets loaded with the page (like application.js), I include a function that watches for a table row with class "row_class" to be updated.

$(document).ready(function(row_class, row_id_prefix){

$("." + row_class).on("ajax:success",function(event, data, status, xhr){
    var parsed_data = jQuery.parseJSON(data); //parses string returned by controller into json object

    var id = parsed_data["id"];
    var new_row = parsed_data["new_row"]; //this is an html string that replaces the existing table row

    $('tr#' + row_id_prefix + id).replaceWith(new_row);
    $('tr#' + row_id_prefix + id).effect('highlight');
    $('.best_in_place').best_in_place(); //activates in-place-editing for newly added content.      
}));        

You can modify the jQuery to update any DOM element you need. Also, if you need the results of ruby methods called on objects (such as a humanized total, tax total, etc) you can define these as variables in the JSON object in the controller.

Ultimately it'd be best if best_in_place would trigger (in this case) the items/update.js.erb script, but it doesn't look like that's on the roadmap.