0

I'm building a jQuery function that allows users to add additional fields to a form. The form has four buttons, for different donation values. When you click on one, it generates the appropriate form fields, and adds an option for an additional donation.

For some reason, the additional donation buttons don't work. The code for the buttons is exactly the same, so this makes no sense to me.

Here's the HTML:

<h6>Donation Information</h6>
<p>
    <a class="button" data-value="500" href="#" style="margin-right:2px;">5" &ndash; $500</a>
    <a class="button" data-value="250" href="#" style="margin-right:2px;">4" &ndash; $250</a>
    <a class="button" data-value="100" href="#"  style="margin-right:2px;">3" &ndash; $100</a>
    <a class="button" data-value="50" href="#" style="padding-right:13px;">2.5" &ndash; $50</a>
</p>
<div id="donationTarget"></div>

And here's the jQuery:

$(".button").click(function(e) {
    e.preventDefault();
    if ($(this).hasClass("clicked")) {
        // do nothing
    } else if ($(this).hasClass("disabled")) {
        // do nothing
    } else {
        $(this).addClass("clicked");
        $(".button:not(.clicked)").addClass("disabled");
        var counter = $(".donation").length;
        var amount = $(this).attr("data-value");
        if (amount == 500) {
            var size = 5;
        } else if (amount == 250) {
            var size = 4;
        } else if (amount == 100) {
            var size = 3;
        } else if (amount == 50) {
            var size = 2.5;
        }
        $("#donationTarget").before("<div class=\"donation\"><input maxlength=\"60\" name=\"inscription" + counter + "\" placeholder=\"Inscription (60 character maximum)\" type=\"text\" /><p><strong>Color Preference (subject to availability):</strong></p><div class=\"half\"><input id=\"color-blue" + counter + "\" type=\"radio\" name=\"color" + counter + "\" /><label for=\"color-blue" + counter + "\">Blue</label><div style=\"clear:both;\"></div><input id=\"color-orange" + counter + "\" type=\"radio\" name=\"color" + counter + "\" /><label for=\"color-orange" + counter + "\">Orange</label><div style=\"clear:both;\"></div><input id=\"color-red" + counter + "\" type=\"radio\" name=\"color" + counter + "\" /><label for=\"color-red" + counter + "\">Red</label><div style=\"clear:both;\"></div></div><!--/.half--><div class=\"half\"><input id=\"color-yellow" + counter + "\" type=\"radio\" name=\"color" + counter + "\" /><label for=\"color-yellow" + counter + "\">Yellow</label><div style=\"clear:both;\"></div><input id=\"color-green" + counter + "\" type=\"radio\" name=\"color" + counter + "\" /><label for=\"color-green" + counter + "\">Green</label><div style=\"clear:both;\"></div></div><!--/.half--><div style=\"clear:both;\"></div></div><br /><h6>Additional Donation</h6><p><a class=\"button\" data-value=\"500\" href=\"#\" style=\"margin-right:2px;\">5\" &ndash; $500</a><a class=\"button\" data-value=\"250\" href=\"#\" style=\"margin-right:2px;\">4\" &ndash; $250</a><a class=\"button\" data-value=\"100\" href=\"#\"  style=\"margin-right:2px;\">3\" &ndash; $100</a><a class=\"button\" data-value=\"50\" href=\"#\" style=\"padding-right:13px;\">2.5\" &ndash; $50</a></p>");
    }
});

Also, is there a way to clean up the super long line of jQuery towards the end of the function? I can't figure out how to keep the HTML on multiple lines without breaking the script.

Thanks.

jsFiddle: http://jsfiddle.net/aptwt/2/

JacobTheDev
  • 17,318
  • 25
  • 95
  • 158

2 Answers2

4

For dynamically added elements, you'll need to use delegated events with the on function:

HTML

<p id="button-container">
    <a class="button" data-value="500" href="#" style="margin-right:2px;">5" &ndash; $500</a>
    <a class="button" data-value="250" href="#" style="margin-right:2px;">4" &ndash; $250</a>
    <a class="button" data-value="100" href="#"  style="margin-right:2px;">3" &ndash; $100</a>
    <a class="button" data-value="50" href="#" style="padding-right:13px;">2.5" &ndash; $50</a>

</p>

jQuery

$(function() {
    $("#button-container").on('click', ".button", function(e) {
    ...
    });
});
cfs
  • 10,610
  • 3
  • 30
  • 43
  • Thanks! Makes sense, just wasn't aware of that. What about my question towards the end of the post? Is there a way for me to make that super long line of jQuery in to multiple lines? – JacobTheDev Jun 11 '13 at 18:21
  • I don't think so, though you could take advantage of mixing double and single quotes so that you don't have to escape the double quotes. It also can be more readable if ou to format the String so that it looks a little more like HTML. http://stackoverflow.com/questions/242813/when-to-use-double-or-single-quotes-in-javascript – cfs Jun 11 '13 at 18:38
0

The issue here is that those new buttons don't have event listeners attached to them. When you write $('.button').click(...), jQuery goes through and attaches an onClick event listener to each element with the button class. Those new elements weren't present on the page when that happened, though.

So, you have to options here. One, you can add the event listener again, but that's not DRY or optimal. Two, you can attach the event listener to a parent element and take advantage of event bubbling using jQuery.on() like so:

<p id="additional-donation"> /* ... */ </p>

$('#additional-donation').on('click', '.button', function(e) {
    var amount = $(e.target).data('value');
    /* ... */
});

Edit: Looks like I was beaten to the punch here. As for your additional questions about formatting that better, you can build the element incrementally by creating the parent, appending child elements, and inserting the parent into the page. Just be sure to do all of that work in JavaScript before inserting the whole thing into the page in one step. That minimizes the amount of DOM manipulation.

var additional = $('div#additional-donation');
additional.append(/* ... */);
$('#donationTarget').before(additional);
Derek Peterson
  • 593
  • 2
  • 8