I've got some javascript (1) monitoring for clicks on a Navigation #element, and it works wonderfully. It's a basic $('#element').click(function()).
However, I've got some other javascript (2) that "renders" the content within the Navigation element, essentially refreshing it. From what I can see, the output HTML is identical enough to the initial HTML, i.e. I haven't fundamentally broken.
Once this javascript (2) has executed, and rendered the Navigation again, my original javascript (1) no longer works.
Is there something in $(document).ready() that I need to understand? Does it attach to those objects that aren't the same when the render happens? Do I need to use something other than $(document).ready(), or do I need to reload the javascript too?
What am I misunderstanding here?
For reference, this is my basic code, with application.html rendering the _nav template:
application.html.erb
<%= content_tag "nav", id: "stages-nav", data: {progress_overall: @progress_overall} do %>
<%= render 'home/nav', current_progress: @progress_overall %>
<% end %>
_nav.html.erb
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav_item" id="business_costs_nav_item"><a href="javascript:void(0);"><span class="small">step 2: </span>Business Costs</a></li>
<li class="nav_item" id="wedding_costs_nav_items"><a href="javascript:void(0);"><span class="small">step 3: </span>Wedding Costs</a></li>
...etc
</ul>
application.js
$(document).ready(function() {
// BUSINESS COSTS
$('#business_costs_nav_item').click(function() {
slide_current_to_new('business_costs')
})
});
All of the above works fine.
However, elsewhere in my application, here is the js that renders the #stages-nav:
show_updated_view.js.erb
// updates the stages-nav to give me my current progress
$('#stages-nav').html("<%= escape_javascript(render('home/nav', current_progress: progress )) %>");
I've double-checked the output of the HTML once the above has run, and it looks identical to prior to running, so pretty certain I haven't malformed my page. If I've done this render incorrectly, would love to know, but looks OK to me.
I'm guessing it's got to be a $(document).ready thing, but would love some help on this!
CodePudding user response:
Your code is attaching an event handler directly to the elements as soon as the document is ready to be manipulated. Since the elements in your js.erb
file are added to the DOM later with an AJAX call then they do not have an attached event handler.
This is not specific to Rails and applies whenever you are adding elements dynamically to the DOM. The solution is to use event delegation:
$(document).on('click', '#business_costs_nav_item', function() {
slide_current_to_new('business_costs');
});
This will catch the click event as it bubbles up to the top of the DOM and works with dynamically inserted elements. This code does not need to wrapped in a jQuery.ready handler since it does not attach event handlers directly to the elements.
The equivilent in vanilla JS is:
document.addEventListener('click', (event) => {
if (!event.target.matches('#business_costs_nav_item')){
return;
}
slide_current_to_new('business_costs');
});