I am a novice at JavaScript an jQuery. I am writing a project and trying to incorporate $(this) to read a data attribute. Once the data attribute is determined and assigned to a variable, I intend to use that to access other form elements.

Instead of reading the data attribute as intended, clicking the button is submitting the form.

This is a code sample:

<fieldset class="new_inputs" id="new_inputs1">
    <label for="file_input_1">Input File:1</label>
    <input class="fileRenamingFormInput" name="file_input_1" id="file_input_1" type="text" value="">
    <br>
    <select class="fileRenamingFormSelect" name="destinationFile_1 id="destinationfile_1">...</select>
    <input class="fileRenamingFormFileOut" name="file_out_1" id="file_out_1" type="text" value="">
    <br>
    <textarea class="copyCommandBlock" name="copyCommandBlock1" id="copyCommandBlock1"></textarea>
    <button type="submit" class="btnGenerate" id="btnGenerate1" data-idx="1">Generate command</button>  <- Button Javascript might act on
    <button type="submit" class="btnCopy" id="btnCopy1" data-idx="1">Copy</button>
</fieldset>

<fieldset class="new_inputs" id="new_inputs2">
    <label for="file_input_2">Input File:2</label>
    <input class="fileRenamingFormInput" name="file_input_2" id="file_input_2" type="text" value="">
    <br>
    <select class="fileRenamingFormSelect" name="destinationFile_2 id="destinationfile_2">...</select>
    <input class="fileRenamingFormFileOut" name="file_out_2" id="file_out_2" type="text" value="">
    <br>
    <textarea class="copyCommandBlock" name="copyCommandBlock2" id="copyCommandBlock2"></textarea>
    <button type="submit" class="btnGenerate" id="btnGenerate2" data-idx="2">Generate command</button> <- Button Javascript might act on
    <button type="submit" class="btnCopy" id="btnCopy2" data-idx="2">Copy</button>
</fieldset>

This is the JavaScript

$("button.btnGenerate").click(function(e){
    e.preventDefault();
    var idx = $(this).data("idx");
    console.log(idx);
});

The logic I am seeking to employ is:

  • When "button.btnGenerate" is clicked, don't submit the form
  • assign data-idx to variable idx
  • once I have variable idx, I can more efficiently use it plus text strings to get form values from sibling or other form elements. For example, if var idx = 2;

    var fnIn = document.getElementById(fileinput'+'idx').value
    var fnOut = document.getElementById(fileout'+'idx').value
    var str = 'cp '+fnIn+' '+fnOut;
    document.getElementById('copyCommandBlock'+idx).value = str;

With the page loaded in the browser there could be multiple fieldsets. They are created dynamically based on the user clicking a button to add another set of fields. I am using $("button.btnGenerate") as the listening event for it is generic.

Is that selector still too generic since it is a class?

Thanks for taking the time to read this. Hope someone can help

Recommended Answers

You must use .on() with code dynamically inserted into the DOM.

Jump to Post

All 12 Replies

It's fine to use that as the selector. Use an #id when there is only one per page. Otherwise, using .classes makes sense.

The Javascript that you have does, indeed, not submit the form, and stick the value of data-idx into the idx variable.

Trying to troubleshoot this, I am really at my wit's end. In sandbox tests I have done, the code works as designed. By sandbox, I mean a stripped down static minimal version of the code.

Trying it on the development version of this project, if I set Developer Tools debug on the line '(e).preventDefault();' and click the button there is no return from jQuery. There are other buttons on this site that have '(e).preventDefault();' and jQuery provides a response such as:

e = jQuery.Event {originalEvent: MouseEvent, type: "click", isDefaultPrevented: ƒ, timeStamp: 911174.1000000002, jQuery112405340923011436065: true, …}

I have tried to run the code in Incognito so no other plug-ins or extensions might interfere. Something appears to interfere if

$("button.btnGenerate").click(function(e){
    e.preventDefault();
    var idx = $(this).data("idx");
    console.log(idx);
});

executes and submits the form

Are you doing e.preventDefault() or (e).preventDefault()?

e.preventDefault();

The discrepancy was a mistyping here, not a copy and paste of bad code.

Is the html code available when the javascript runs? Are you putting the JS code inside the $(document).ready(function() { } );? You might also want to look at using .on() instead, such as something like $(document).on('.btnGenerate', 'click', function(event) { } );

Note I just typed this code out manually so it might have a typo.

@Dani: "Is the html code available when the javascript runs?"

If you mean fully formed in the browser, yes. These fieldsets that appear as an example in my original post and the button I am clicking on are rendered by JavaScript. The code I am clicking and the data expected to be acted upon/returned are fully formed in the browser window and perfect from a syntax point of view.

Is there a difference between code that is hard-coded in an HTML file and then displayed in the browser versus DOM elements (i.e., fieldsets, div's, HTML appended to forms) placed in the DOM by JavaScript/jQuery?

Your raising this question was another possibility I wanted to explore. Testing I did was with hard-code HTML and the JavaScript worked as intended. It is with code that is placed in the DOM by JavaScript/jQuery that the page is reacting to submit the form.

The JavaScript is wrapped in 'document.ready' tags. I am planning to try .on() instead of .click()

You must use .on() with code dynamically inserted into the DOM.

Using .on() is the solution! Thanks a lot for your help, Dani!

To anyone else reading this to find a solution to a challenge they might be having, the complete solution is not simply a case of changing

$("button.btnGenerate").click(function(e){
    e.preventDefault();
    var idx = $(this).data("idx");
    console.log(idx);
});

to

$("button.btnGenerate").on("click", (function(e){
    e.preventDefault();
    var idx = $(this).data("idx");
    console.log(idx);
});

To understand the use of .on() Google "jquery .on for elements dynamically added" to understand the constraints. It is important that the event be bound to an element of the DOM that is hard-coded/not added to the DOM dynamically by JavaScript/jQuery. The code cited in my original post is added dynamically. Therefore so are the buttons with the class btnGenerate. It is necessary to bind the event to a DOM element farther up that is NOT added dynamically. From my original post, one or more code blocks wrapped with <fieldset> are appended to form . Therefore, the JavaScript becomes:

$("form").on("click", ".btnGenerate", function(e){
    e.preventDefault();
    var idx = $(this).data('idx');
    console.log(idx);
});

The page/browser behaves as intended and the information appears in the console instead of the click triggering a form submission.

The answer of Dani is of course the correct one ,

You must use .on() with code dynamically inserted into the DOM.

But let me write more about that because it is an interesting topic often misunderstood , when we assign an event to a DOM element or in a set using jQuery , it uses Sizzle parser to find those elements. Of course it searches the DOM elements that are there , and not the ones that will be created in the future. So anything you write as jQuery event will not work for elements that will created in the future. There are two work around for that , based in the type of the front end app.
The first one is what Dani mentioned , using the .on() event in the parent node. And guessing that you don't know the parent node , in document.
e.g.

        $(document).on("click", "button.btnGenerate", function(){
            // and here goes the onClick function
        });

But if your front end app can have a starting point and many different cases like that it would be more efficient / readable to have them all in one place e.g.

        $(document).click(
            function(event)
            {
                var $obj = $(event.target);
                if($obj.is("button"))
                {
                    if($obj.hasClass("btnGenerate"))
                    {
                        // here goes the code 
                    }
                    //some other cases for buttons 
                }
                // some other cases for elements that are not buttons 
            }
        );

And finally one comment , Sizzle is a great achievement and is another project from jQuery not getting enough attention , so for my part - thank you Sizzle team -

Sorry for my lack of a detaled explanation, but I wrote my last post from my iPhone while in bed. Thank you for filling in the details to help others!!

You would not need to provide a preventDefault() call if you were not using a button with a type attribute of "submit". Just use type="button" for such cases when you do not intend to submit the form.

I keep form submission in place and use it as a failover if jQuery fails for some reason. I think it also improves site accessibility.

commented: Being Semantic isn't Pedantic. Submit if you are going to submit, sod js. +5