简体   繁体   中英

Rails 6: execute a JS function after rendering partial

Rails & Javascript beginner here,

On a training project, I made flash messages disappear after few seconds using JQuery. A visitor would send AJAX request to add a product to his cart, then a flash partial 'Added to cart' appears and automatically fades out after few seconds.


# application.html.erb

<div id='flash' class='flex-column'>
   <%= render partial: 'shared/flash'  %>
</div>
# shared/_flash.html.erb

<% flash.each do |key, value| %>
  <%= display_flash(key, value) %>
  <%= javascript_pack_tag 'custom/flash' %>  
  # this works, but injects the script each times the partial is rendered
<% end %>
# helpers/application_helper.rb

def display_flash(key, value)
  def display_flash(key, value)
    div_class = [flash_class(key), 'text-center fade show alert-dismissible'].join(' ')

    content_tag(:div, class: div_class) do
      content_tag(:p, value) +
      button_tag(class: 'ml-auto close', 'data-dismiss': 'alert', type: 'button') do
        content_tag(:span, '&times;'.html_safe, 'aria-hidden': 'true') +
        content_tag(:span, 'Close', class: 'sr-only')
      end
    end
  end
end
// app/javascript/packs/custom/flash.js

function closeFlash(){
  let lastAlert = $('#flash .alert:last')

  function fadeFlash() {
    lastAlert.animate( {opacity: 0}, 2000, function() {
      $(this).hide('slow', function() {
        $(this).remove()
      });
    });
  };

  setTimeout(fadeFlash, 2000)
};

closeFlash();

The issue with this is that it pollutes my DOM with unnecessary <script> tags: 不需要的脚本标签

This could be fixed, but is there a suitable way to execute one specific javascript function after rendering a (AJAX) partial? In my case, executing closeFlash() located in packs/custom/flash.js each time a partial is rendered.

Thanks for your help and your time


EDIT Solution:

From Amit Patel answer and this post

// app/javascript/packs/custom/flash.js

window.closeFlash = function() {
    let lastAlert = $('#flash .alert:last')

    function fadeFlash() {
        lastAlert.animate( {opacity: 0}, 2000, function() {
            $(this).hide('slow', function() {
                $(this).remove()
            });
        });
    };

    setTimeout(fadeFlash, 2000)
};
 // app/javascript/packs/custom/flash.js window.closeFlash = function() { let lastAlert = $('#flash.alert:last') function fadeFlash() { lastAlert.animate( {opacity: 0}, 2000, function() { $(this).hide('slow', function() { $(this).remove() }); }); }; setTimeout(fadeFlash, 2000) };

It doesn't inject the whole function but (I believe) the minimal javascript code to call it.

Move <%= javascript_pack_tag 'custom/flash' %> to your layout or your application.js` so that it is available across the app.

modify your template like

application.html.erb

<div id='flash' class='flex-column'>
   <%= render partial: 'shared/flash'  %>
   <script>
     $(function(){
       closeFlash();
     });
   </script>
</div>

A more recent approach would be to set a Stimulus controller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM