1

I have encountered an issue with my code, while developing a project. I dynamically add a login form to a certain div in the DOM-Tree. It is all nice and fine, all elements are generated and all attributes are added, but I cannot access either of the fields, let alone submit it. Can somebody please spot the issue within?

loginArea.click((e) => {
    e.preventDefault();

    loginArea
        .empty()
        .append(
            $(document.createElement('form'))
                .attr({id: 'user__loginform'})
                .append(
                    $(document.createElement('p'))
                    .addClass('user__action')
                    .text('Please enter your credentials!')
                )
                .append(
                    $(document.createElement('input'))
                    .prop({
                        type: 'email',
                        id: 'login_mail',
                    })
                    .attr({
                        placeholder: 'Please enter a valid e-mail adress!',
                        required: true,
                        form: 'user__loginform'
                    })
                )
                .append(
                    $(document.createElement('input'))
                    .prop({
                        type: 'text',
                        id: 'login_pw',
                    })
                    .attr({
                        placeholder: 'Please enter a password!',
                        minglength: 9,
                        maxlength: 16,
                        required: true,
                        form: 'user__loginform'
                    })
                )
                .append(
                    $(document.createElement('input'))
                    .attr({
                        form: 'user__loginform',
                        type: 'submit',
                        value: 'Login'
                    })
                )
        )
});

Thank you a lot in advance

EDIT:

Incorporating the input I have received, I have shortened the function to this, and added .off() at the end. This seems to solve the issue I had, as for now the dynamically generated input can be filled out.

signupArea.click((e) => {
    e.preventDefault();

   let formTemplate = `
        <div id="form-template" class="user__action">
            <form id="user__registform">
                <p>Please enter your preferred credentials!</p>
                <input type="email" id="regist_mail" placeholder="Please enter a valid e-mail!" required="required" form="user__registform">
                <input type="text" id="regist_pw" placeholder="Please enter a password!" minglength="9" maxlength="16" required="required" form="user__registform">
                <input form="user__registform" type="submit" value="Register" class="user__regist--submit">
            </form>
        </div>
    `;
    signupArea.html(formTemplate);
    signupArea.off();
});
  • Why do you use `$(document.createElement("form"))` instead of `$("
    ")`?
    – Barmar Mar 08 '21 at 19:54
  • Please post a [mcve]. You can use a [Stack Snippet](https://meta.stackoverflow.com/questions/358992/ive-been-told-to-create-a-runnable-example-with-stack-snippets-how-do-i-do) to make it executable. – Barmar Mar 08 '21 at 20:00
  • Why create the form dynamically? Put it in the HTML and use `.show()` to make it visible. – Barmar Mar 08 '21 at 20:01
  • Well, honestly, this is the way I do know, and could solve the problem. Should I add it in the HTML, set display to none and alter the CSS on click? – Tamás Szkok Mar 09 '21 at 13:32
  • That's how I would recommend doing it. – Barmar Mar 09 '21 at 17:07

1 Answers1

1

The issue is because you've bound the click handler to the loginArea element, yet every time you click that element, or importantly an element within it, the event bubbles back up and fires the event again, which clears the content and re-inserts a fresh form element.

To fix this you could add the event which adds the form to an element outside of loginArea, like this:

$('#foo').click((e) => {
  e.preventDefault();

  $('#loginarea')
    .empty()
    .append(
      $(document.createElement('form'))
      .attr({
        id: 'user__loginform'
      })
      .append(
        $(document.createElement('p'))
        .addClass('user__action')
        .text('Please enter your credentials!')
      )
      .append(
        $(document.createElement('input'))
        .prop({
          type: 'email',
          id: 'login_mail',
        })
        .attr({
          placeholder: 'Please enter a valid e-mail adress!',
          required: true,
          form: 'user__loginform'
        })
      )
      .append(
        $(document.createElement('input'))
        .prop({
          type: 'text',
          id: 'login_pw',
        })
        .attr({
          placeholder: 'Please enter a password!',
          minglength: 9,
          maxlength: 16,
          required: true,
          form: 'user__loginform'
        })
      )
      .append(
        $(document.createElement('input'))
        .attr({
          form: 'user__loginform',
          type: 'submit',
          value: 'Login'
        })
      )
    )
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="foo">Click me to add form</button>
<div id="loginarea"></div>

You should also note that the logic you're using to create the form is unnecessarily long winded and not a good separation of concerns.

A much better approach is to store a template in your HTML and use it to create the new dynamic content. This way if you need to make a change to the form layout in the future it can be done directly in the HTML. The JS becomes completely agnostic of the UI. Try this:

$('#foo').click((e) => {
  e.preventDefault();

  let formTemplate = $('#form-template').html();
  $('#loginarea').html(formTemplate);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="foo">Click me to add form</button>
<div id="loginarea"></div>

<script type="text/html" id="form-template">
  <form id="user__loginform">
    <p class="user__action">Please enter your credentials!</p>
    <input type="email" id="login_mail" placeholder="Please enter a valid e-mail adress!" required="required" form="user__loginform">
    <input type="text" id="login_pw" placeholder="Please enter a password!" minglength="9" maxlength="16" required="required" form="user__loginform">
    <input form="user__loginform" type="submit" value="Login">
  </form>
</script>
Rory McCrossan
  • 306,214
  • 37
  • 269
  • 303
  • Thank you for the input. It is certainly a partial solution, as my cody is significantly shorter, but at the same time the basic issue hasn't been adressed, as I am still unable to fill either fields of the generated inputs. – Tamás Szkok Mar 09 '21 at 10:00
  • 1
    The example works correctly as the event handler has been bound to an element other than the container of the form. That's the main change you need to make. If you've made that change and it still isn't working, please edit the question to include your updated code. – Rory McCrossan Mar 09 '21 at 10:01
  • 1
    I have found a go-around for it, as I have posted. After I removed the event listener for onclick at the end of the function, I was able to fill out the forms. Thank you a lot for your aswer, so that I could solve the whole problem. – Tamás Szkok Mar 09 '21 at 13:29