Tamás Szkok
Tamás Szkok

Reputation: 17

Dynamically generated input fields cannot be filled

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();
});

Upvotes: 1

Views: 410

Answers (1)

Rory McCrossan
Rory McCrossan

Reputation: 337590

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>

Upvotes: 1

Related Questions