使用jQuery在HTML元素中生成动态ID

时间:2019-03-25 01:17:20

标签: javascript jquery html forms

我内置了一个Web简历生成器,以学习如何为Web开发。我制作了一个HTML表单,用户可以添加更多字段来添加有关他的更多信息。示例:他具有多个专业经验,但是该表格以一个prof-exp字段开头。因此,他单击“添加新exp”按钮,然后JS为此创建了一个新字段。我使用了jQuery的clone()方法来执行此操作,但这使我遇到了下面列出的问题。另外,这是我编写的代码:

var index = 0;
$(document).ready(() => {
    $("#add-exp").click(() => {
        $("#professional").clone().attr("id", "professional" + index++).
        appendTo("#professional-info").find("select, input, textarea").val("");
    })
})
<!DOCTYPE html>
<html>


<body>

<form action="" method="GET" id="main">
  <fieldset id="professional-info">
                <legend><h2>professional experience</h2></legend>
                <div id="professional">
                    <label for="level">Nível: <select name="level" id="level" >
                        <option value="empty">Selecione</option>
                        <option value="estagio">Estágio</option>
                        <option value="junior-trainee">Junior/Trainee</option>
                        <option value="aux-opera">Auxiliar/Operacional</option>
                        <option value="pleno">Pleno</option>
                        <option value="senior">Sênior</option>
                        <option value="sup-coord">Supervisão/Coordenação</option>
                        <option value="gerencia">Gerência</option>
                    </select></label>
                    <label for="position"> Cargo: <input type="text" name="carrer" id="carrer" ></label><br>
                    <label for="company"> Empresa: <input type="text" name="company" id="company" ></label><br>
                    <label for="begin"> Início: <input type="month" name="begin" id="begin" ></label>
                    <label for="break"> Término: <input type="month" name="break" id="break" ></label>
                    <label for="stl-work"><input type="checkbox" name="stl-work" id="stl-work" >Ainda trabalho aqui</label><br>
                    <label for="job-desc"> Descrição: <textarea name="job-desc" id="job-desc"  placeholder="Conte um pouco sobre o que você fazia lá." cols="40" rows="1"></textarea></label>
                    <button type="button" id="remove-exp" >Remove this professional xp</button>
                </div>
                <button type="button" form="main" id="add-exp">Add other professional exp</button> 
            </fieldset>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</body>
</html>

问题是:

  • 只有div具有动态ID,这会导致以下两个其他问题;

  • 我不知道如何实现删除按钮逻辑,因为我无法区分第一个按钮和其他div中的其他按钮;

  • 由于标签使用其对应的输入ID进行引用,因此当用户单击标签时,它们将指向第一个字段输入;

我希望你们能理解我的问题并帮助我。另外,对不起我的英语-我也在学习。谢谢你们!

4 个答案:

答案 0 :(得分:0)

如果您已经将输入内容包装在标签中,则不再需要ID, 并且您可以将this用作删除按钮的参数,以便可以使用它来删除您的区块。

请检查以下示例

$(function(){
	// keep the first block hidden as an empty template 
	$('.form-row:first').hide();
	// trigger add new item
	AddItem();
})
function AddItem(){
	var container = $('#container');
	// clone the form, show it & append before add button
	var cloned = $('.form-row:first').clone().show().insertBefore($('#addBtn'));
}
function RemoveItem(elm){
	// get form element & remove it
	$(elm).closest('.form-row').remove()
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<style type="text/css">
.form-row {border:1px solid #ccc; margin:5px 0;padding:10px;}
</style>
<div id="container">
	<div class="form-row">
		<!-- wrap your input inside label tag to avoid using id as reference -->
		<label>Field 1 : <input type="text" name="field1"></label>
		<label>Field 2 : <input type="text" name="field2"></label>
		<input type="button" value="Remove this item" onclick="RemoveItem(this)">
	</div>
	<input id="addBtn" type="button" value="Add new item" onclick="AddItem()">
</div>

答案 1 :(得分:0)

如建议的那样,Vue.js很酷,但是 jQuery 也具有一些被遗忘的功能。

而且,由于您是动态创建元素的,因此请勿使用ID。
然后将您的体验以数组[]的形式提交给后端:即name="carrer[]"name="company[]"等。在后端循环上,这些数据数组可以检索所有用户体验。

const new_exp = () => $('<div>', {
  'class': 'professional-exp',
  html: `
       <label>Nível:
         <select name="level[]">
           <option value="empty">Selecione</option>
           <option value="estagio">Estágio</option>
           <!-- etc... -->
         </select>
      </label>
      <label>Cargo: <input type="text" name="carrer[]"></label><br>
      <label>Empresa: <input type="text" name="company[]"></label><br>
      <label>Início: <input type="month" name="begin[]"></label>
      <label>Término: <input type="month" name="break[]" ></label>
      <label><input type="checkbox" name="stl-work[]"> Ainda trabalho aqui</label><br>
      <label>Descrição: <textarea name="job-desc[]" placeholder="Conte um pouco sobre o que você fazia lá." cols="40" rows="1"></textarea></label><br>
     `,
  append: $('<button>', {
    type: 'button',
    text: 'Remove',
    click() {
      $(this).closest('.professional-exp').remove();
    }
  }),
  appendTo: '#professional',
});


jQuery($ => { // DOM ready and $ alias in scope

  new_exp();                          // On init (Create first exp)
  $("#new_exp").on('click', new_exp); // On click

});
.professional-exp {
  padding: 10px;
  margin-bottom: 10px;
  background: #eee;
}
<form action="" method="POST" id="main">
  <fieldset>
    <legend>
      <h2>Professional experience</h2>
    </legend>
    <div id="professional"></div>
    <button type="button" id="new_exp">+ Add more</button>
  </fieldset>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

上面我们在模板中定义了Remove的button动作,但是如果您愿意,还可以将按钮硬编码到模板中,并创建动态点击处理程序(使用jQuery的.on()),如下所示:

const exp_new = () => $('<div>', {
  'class': 'professional-exp',
  html: `
     <label>Nível:
       <select name="level[]">
         <option value="empty">Selecione</option>
         <option value="estagio">Estágio</option>
         <!-- etc... -->
       </select>
    </label>
    <label>Cargo: <input type="text" name="carrer[]"></label><br>
    <label>Empresa: <input type="text" name="company[]"></label><br>
    <label>Início: <input type="month" name="begin[]"></label>
    <label>Término: <input type="month" name="break[]" ></label>
    <label><input type="checkbox" name="stl-work[]"> Ainda trabalho aqui</label><br>
    <label>Descrição: <textarea name="job-desc[]" placeholder="Conte um pouco sobre o que você fazia lá." cols="40" rows="1"></textarea></label><br>
    <button class="exp_delete">REMOVE</button>
  `,
  appendTo: '#professional',
});



jQuery($ => { // DOM ready and $ alias in scope

  exp_new();                          // On init (Create first exp)
  $("#exp_new").on('click', exp_new); // and on click.
  $('#main').on('click', '.exp_delete', ev => $(ev.target).closest('.professional-exp').remove());

});
.professional-exp {
  padding: 10px;
  margin-bottom: 10px;
  background: #eee;
}
<form action="" method="POST" id="main">
  <fieldset>
    <legend>
      <h2>Professional experience</h2>
    </legend>
    <div id="professional"></div>
    <button type="button" id="exp_new">+ Add more</button>
  </fieldset>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

答案 2 :(得分:0)

演示代码的详细信息在代码本身中进行了注释。 <fieldset><button>的某些类进行了较小的更改。结构有所更改,因此请记住这一点。 jQuery是通用的,它允许您泛化DOM操作并消除对id的依赖-仅使用类是很有可能的。

注册到动态标签的事件将失败,除非您委派事件。要将click事件委托给当前和将来存在的所有按钮,请注册一个按钮通常共享的祖先标记(例如#main)。然后在第二个参数(事件数据)中分配按钮的选择器:

$('#main').on('click', '.add, .remove', function(e) {...  

关于通过单击嵌套按钮来删除a的方法-$(e.target)$(this)可用于引用当前单击的按钮。当您需要找到单击按钮的合适祖先(例如.professional)时,请使用.closest()方法,如下所示:

$(e.target).closest('.professional').remove();

演示

let index = 0;
// Hide the first .remove button
$('#remove').hide();
/*
Register the form to the click event 
Event data directs .add and .remove buttons
*/
$("#main").on('click', '.add, .remove', function(e) {
  // if the clicked button has .add
  if ($(this).hasClass('add')) {
    /*
    clone the first .professional
    increment counter
    Reference all form controls of the clone
    on each form control modify its id 
    */
    const dupe = $(".professional:first").clone(true, true);   
    index++;
    const formControls = dupe.find('select, button, input, textarea');
    formControls.each(function() {
      let ID = $(this).attr('id');
      $(this).attr('id', ID + index);
    });
    
    /*
    Remove the legend from clone
    Show the .add and .remove on clone
    Hide the clicked button
    Add clone to form
    Stop event bubbling
    */
    dupe.find('legend').remove();
    dupe.find('.add, .remove').show();
    $(e.target).hide();
    $('#main').append(dupe);
    e.stopPropagation();
  // Otherwise if clicked button has .remove...  
  } else if ($(e.target).hasClass('remove')) {
    /*
    Find clicked button ancestor .professional and remove 
    it.
    Hide all .add buttons
    Show the last .add
    Stop event bubbling
    */
    $(e.target).closest('.professional').remove();
    $('.add').hide();
    $('.add:last').show();
    e.stopPropagation();
    
  } else {
    // Otherwise just stop event bubbling
    e.stopPropagation();
  }
});
:root {
  font: 400 14px/1 Consolas
}

fieldset {
  width: fit-content
}

legend {
  margin-bottom: -15px
}

label {
  display: block
}

input,
select,
button {
  display: inline-block;
  font: inherit;
  height: 3ex;
  line-height: 3ex;
  vertical-align: middle
}

.text input {
  width: 24ch
}

select {
  line-height: 4ex;
  height: 4ex;
}

label b {
  display: inline-block;
  width: 7.5ch;
}

button {
  position: absolute;
  display: inline-block;
  height: initial;
  margin: 0;
}

.add {
  position: absolute;
  right: 0;
}

[for=level] b {
  width: 6ch
}

.btn-grp {
  position: relative;
  width: 97%;
  min-height: 26px;
  padding: 0
}
<!DOCTYPE html>
<html>

<head></head>

<body>
  <form action="" method="GET" id="main">
    <fieldset class="professional">
      <legend>
        <h2>Professional Experience</h2>
      </legend>
      <label for="level">
          <b>Nível: </b>
          <select name="level" id="level">
            <option value="empty">Selecione</option>
            <option value="estagio">Estágio</option>
            <option value="junior-trainee">
              Junior/Trainee
            </option>
            <option value="aux-opera">
              Auxiliar/Operacional
            </option>
            <option value="pleno">Pleno</option>
            <option value="senior">Sênior</option>
            <option value="sup-coord">
              Supervisão/Coordenação
            </option>
            <option value="gerencia">
              Gerência
            </option>
          </select>
        </label>
      <fieldset class='text'>
        <label for="carrier"><b>Cargo: </b> 
          <input type="text" name="carrer" id="carrer">
          </label>
        <label for="company"><b>Empresa: </b>
          <input type="text" name="company" id="company">
          </label>
        <label for="begin"><b>Início: </b> 
          <input type="month" name="begin" id="begin">
          </label>
        <label for="break"><b>Término: </b> 
          <input type="month" name="break" id="break">
          </label>
      </fieldset>
      <label for="stl-work">
        <input type="checkbox" name="stl-work" id="stl-work" >Ainda trabalho aqui
        </label>
      <label for="job-desc"><b>Descrição: </b></label>
      <textarea name="job-desc" id="job-desc" placeholder="Conte um pouco sobre o que você fazia lá." cols="35" rows="1"></textarea>
      <fieldset class='btn-grp'>
        <button type="button" id='remove' class='remove'>Remove</button>
        <button type="button" id='add' class="add">Add</button>
      </fieldset>
    </fieldset>
  </form>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</body>

</html>

答案 3 :(得分:-1)

将新的“删除”按钮与其“专业” div相连的一种方法是在事件处理程序中添加一条额外的语句,以将其id与新div的id并行更新,例如:

let lastIndex = index - 1;
$("#professional" + lastIndex).find("button").attr("id", "add-exp" + lastIndex);

(此代码可能没有正确的语法-我不太使用jQuery-但您可以看到这个主意。)

更好的方法可能是,当单击“删除”按钮时,不要根据ID删除,而是找到closest祖先div并删除该div。

对于标签,您应该省略id(因为同一页面上的两个元素都不应具有相同的id)。并且由于输入嵌套在标签中,因此您还应该能够省去for属性并使关联隐式。 (请参见https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label。)