0

I know putting JavaScript in partials is a bad idea because the page will have to load up a new script every time a new partial is loaded. I am aware of and have read this question, but its answer did not work for me (putting the script into app/javascripts/application.js). I think it is because I am working with partials that are dynamically generated onto the page. I think the dynamically generated partial does not react to the script loaded up on the initial page.

For example, I have a "Rule" div with a select input that has a script to do something when the select input is changed. This works for every Rule div that is generated on page load. But then there is also a "+" or "ADD" button which will dynamically generate more Rule divs which do not respond to the script, unless that script is in the partial.

Is there a good way to keep the script out of the partial when the partial is dynamically generated?

3 Answers 3

5

JQuery sets listeners on page load (i.e. $(selector).on(etc.)), so it doesn't listen for events on dynamically added elements. There is a way around it, though. You need to use what is called a delegate.

$(document).ready( function() { 
    $('body').on('change', 'input.selector', function(e) {
        // do something
    });
});

I'm not sure what your event (here I put change) or selector for the select you are using (here I put input.selector), but if you replace those with the appropriate information, it should work even with dynamically added elements.

Sign up to request clarification or add additional context in comments.

3 Comments

OK, so I'm guessing event delegation has something to do with using body (as opposed to the dynamically generated div). So 'body' knows that its select elements do something on change, and it doesn't matter when they're added. Is that correct? ... Unfortunately, your code doesn't work for me. I copied it word for word, except I changed "do something" to a console.log("hello"); but I couldn't get the "hello" to log.
You have the right idea. The code I pasted won't work unless you are watching for inputs with the class selector, which I imagine you aren't. Replace input.selector with the selector for the inputs you want to watch for changes on.
Sorry! I had to work on something that held higher priority before coming back to this. I feel silly about not knowing how to replace input.selector now. And one more thing, it was necessary to have the listener inside of $(document).ready( function() { }); It's working fantastic with my dynamic partials now. Thank you!
2

You can use JQuery to execute the code only after the document has loaded onto the DOM:

$( document ).ready(function() {
    //Call your functions here
});

That way, your JS will have access to whatever is on the page, because you are ensuring that it is fully loaded.

If your divs are not in place on document ready, you can use event delegation, as suggested by ptd. Basically what this means is that you install a handler on a parent div (which will be present on document ready) which says, "hey, when you click on this dynamic div inside of me, call this function".

$('div#master').on('click', 'div.dynamic', function(event) { 
    console.log("action here") 
    var $dynamicDiv = $(event.currentTarget) //The current Target is the thing you clicked on, not the parent.
});    

4 Comments

This doesn't work :( Just tried it to confirm that it doesn't work to make sure. The dynamically generated divs are not actually on the page when the document is "ready". They are created after, when the user presses a button.
Sounds like you already have an Event handler for when a user clicks on a button. At that same time, you should install another event handler on the div that you are putting on the page. $( "div.new_div" ).on("click", function(){ //install new handler here })
Wouldn't that still add a script for each new div's handler?
Yes. The solution indeed is event delegation. You can use ptd's code. But it can be more specific, so if all of your divs that you are adding will be within one master div, you can do event delegation on it. $('div#master').on('click', 'div.dynamic', function(event) { console.log("action here") });
1

If you are adding elements to the DOM using AJAX calls, but want to keep your JavaScript in your assets folder only, here's a quick and clean way to accomplish this.

// /app/assets/javascript/foo.js

// On intial page load
$(document).ready(function() {
  yourJavaScriptForPartials();
});

// After a subdomain field is loaded via AJAX
$(document).ajaxComplete(function() {
  yourJavaScriptForPartials();
});

function yourJavaScriptForPartials() {
  // Insert your javascript here. 
};

Now, any JavaScript you put in the yourJavaScriptForPartials() function will be available both to the initially loaded DOM, and to any DOM elements added via AJAX. For reference, here is the JQuery page for the ajaxComplete event listener.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.