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

问题描述 投票:-1回答:4

我建立了一个网络简历生成器来学习如何开发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作为参考,当用户点击它时,它们指向第一个字段输入;

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

javascript jquery html forms
4个回答
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的按钮操作,但如果你想要你也可以将按钮硬编码到模板中并创建一个动态点击处理程序(使用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>

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>

0
投票

演示代码的详细信息在代码本身中进行了注释。 <fieldset>s和<button>s的某些课程有一些细微的变化。结构改变了一点,所以记住这一点。 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>

-1
投票

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

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

(这段代码可能没有正确的语法 - 我不会非常使用jQuery - 但你可以看到这个想法。)

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

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

© www.soinside.com 2019 - 2024. All rights reserved.