tec*_*t82 10 javascript jquery
我目前正在处理在表单内生成动态输入字段.我有一个复杂的例子,它使用复选框和选择框.它有两种类型的元素:main_items和sub_items.如上所述,我可以通过一个clone函数动态添加输入字段,该函数复制具有唯一id属性的一组新输入字段.但是我对两件事情有很大的困难:首先,保持id每个复制元素的独特性,特别是对于选择框.其次,我只能得到第一个下拉菜单才能用于第一个项目,但我还没有想出办法为其他项目做这个.的jsfiddle
$('#btnAdd').click(function () {
var num = $('.clonedSection').length;
var newNum = num + 1;
var newSection = $('#pq_entry_' + num).clone().attr('id', 'pq_entry_' + newNum);
newSection.find('input[type="text"]').val('');
newSection.find('select').val('');
newSection.find('input[type="checkbox"]').prop('checked', false);
//hide sub item
newSection.find('.sub-item').hide();
//change the input element selectors to use name
newSection.find('input[name^="first_item_"]').attr('id', 'main_item_' + newNum).attr('name', 'main_item_' + newNum);
newSection.find('input[name^="second_item_"]').attr('id', 'second_item_' + newNum).attr('name', 'second_item_' + newNum);
newSection.find('input[name^="item_count_"]').attr('id', 'item_count_' + newNum).attr('name', 'item_count_' + newNum);
newSection.find('input[name^="sub_item_"]').attr('id', 'sub_item_' + newNum).attr('name', 'sub_item_' + newNum);
newSection.find('input[name^="other_item_"]').attr('id', 'other_item_' + newNum).attr('name', 'other_item_' + newNum);
newSection.insertAfter('#pq_entry_' + num).last();
$('#btnDel').click(function () {
var num = $('.clonedSection').length; // how many "duplicatable" input fields we currently have
$('#pq_entry_' + num).remove(); // remove the last element
// enable the "add" button
$('#btnAdd').prop('disabled', '');
// if only one element remains, disable the "remove" button
if (num - 1 == 1) $('#btnDel').prop('disabled', 'disabled');
});
});
$('#btnDel').prop('disabled', 'disabled');
//Generate Dropdown
$('#item_count_1').change(function() {
var option = $(this).val();
showFields(option);
return false;
});
function showFields(option){
var content = '';
for (var i = 1; i <= option; i++){
content += '<div id="item_'+i+'"><label>Item # '+i+'</label><br /><label>Item Name:</label> <select id="item_name_'+i+'" name="item_name_'+i+'" class="course_list"><option value="" >--- Select ---</option><option value="apples" >apples</option><option value="banana" >banana</option><option value="mango" >mango</option></select></div>';
}
$('#item_names_1').html(content);
}
Run Code Online (Sandbox Code Playgroud)
HTML
<ul id="pq_entry_1" class="clonedSection">
<li style="list-style-type: none;">
<input id="first_item_1" class="main-item" name="main_item_1" type="checkbox"><label>First Item</label>
</li>
<li style="list-style-type: none;">
<input id="second_item_1" class="main-item" name="main_item_1" type="checkbox"><label>Second Item</label>
</li>
<ul class="sub-item" style='display: none;'>
<li style="list-style-type: none;">
<label>
How many items:
<small>required</small>
</label>
<select id="item_count_1" name="item_count_1" class="medium" required>
<option value="">---Select---</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</li>
<li style="list-style-type: none;">
<div id="item_name_1"></div>
</li>
</ul>
</ul>
Run Code Online (Sandbox Code Playgroud)
Ben*_*aum 20
那么,我们来谈谈如何构建基本的GUI应用程序.在我们继续之前,我想让你知道下面的代码可以用Knockout/Angular中的~20 LoC编写,但我选择不这样做,因为那不会真正教给任何人任何东西.
那么,我们来谈谈GUI.
我们希望将它们分开,以便它们可以独立行动.我们想要实际表示用户在JavaScript对象中看到的内容,以便它可以维护,可测试可读等等.有关详细信息,请参阅关注点分离.
那么,每个东西在你的应用程序中有什么作用?
最直观的是从那里开始.
// our item, like we've just described it :)
function Thing(){ //we use this as an object constructor.
this.firstItem = false;
this.subItem = false;
this.secondItem = false;
this.numItems = 0;
this.items = []; // empty list of items
}
Run Code Online (Sandbox Code Playgroud)
嗯,这是一件事,我们现在可以创建它们,new Thing()然后设置它们的属性,例如thing.firstItem = true.
但是我们没有一个 Thing我们有东西.东西只是一个(有序的)一堆东西.有序集合通常由JavaScript中的数组表示,因此我们可以:
var stuff = []; // our list
var thing = new Thing(); // add a new item
stuff.push(thing); // add the thing we just created to our list
Run Code Online (Sandbox Code Playgroud)
我们当然也可以在提交时将此信息传达给PHP.另一种方法是提交一个JSON对象并在PHP中读取它(这很好!),或者我们可以将它序列化为形式参数(如果你对该问题中的方法有任何问题 - 请告诉我).
相当精明.到目前为止,您只有对象,您没有在任何地方指定它们的行为.我们有'数据'层,但我们还没有任何表示层.我们首先要删除所有ID并添加行为.
我们不想克隆现有的对象,而是想要一种'cookie cutter'方式来创建新元素的外观.为此,我们将使用模板.让我们首先提取"项目列表"在HTML模板中的显示方式.基本上,给你的HTML它是这样的:
<script type='text/template' data-template='item'>
<ul class="clonedSection">
<li style="list-style-type: none;">
<label><input class="main-item" type="checkbox" />First Item</label>
<ul class="sub-item" style="display: none;">
<li style="list-style-type: none;">
<label><input type="checkbox" />Sub Item</label>
</li>
</ul>
</li>
<li style="list-style-type: none;">
<label>
<input class="main-item" type="checkbox" />Second Item</label>
<ul class="sub-item" style='display: none;'>
<li style="list-style-type: none;">
How many items:
<select class="medium" required>
<option value="">---Select---</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</li>
<li style="list-style-type: none;"><div></div></li>
</ul>
</li>
</ul>
</script>
Run Code Online (Sandbox Code Playgroud)
现在让我们创建一个'哑'方法,用于在屏幕上显示模板.
var template;
function renderItem(){
template = template || $("[data-template=item]").html();
var el = $("<div></div>").html(template);
return el; // a new element with the template
}
Run Code Online (Sandbox Code Playgroud)
[这是我们的第一个jsfiddle演示演示](http://jsfiddle.net/RLRtv/,它只添加了三个项目,没有任何行为到屏幕上.阅读代码,看到你理解它,不要害怕询问你不明白的位:)
接下来,我们将添加一些行为,当我们创建一个项目时,我们将它耦合到一个Thing.因此,我们可以采用单向数据绑定方式(视图中的更改反映在模型中).如果你感兴趣的话我们可以稍后实现另一个绑定方向,但它不是原始问题的一部分,所以为了简洁起见,我们现在就跳过它.
function addItem(){
var thing = new Thing(); // get the data
var el = renderItem(); // get the element
el. // WHOOPS? How do I find the things, you removed all the IDs!?!?
}
Run Code Online (Sandbox Code Playgroud)
那么,我们在哪里被困?我们需要将行为附加到我们的模板,但普通的HTML模板没有钩子,所以我们必须手动完成.让我们首先使用"数据绑定"属性更改我们的模板.
<script type='text/template' data-template='item'>
<ul class="clonedSection">
<li style="list-style-type: none;">
<label>
<input class="main-item" data-bind = 'firstItme' type="checkbox" />First Item</label>
<ul class="sub-item" data-bind ='subItem' style="display: none;">
<li style="list-style-type: none;">
<label>
<input type="checkbox" />Sub Item</label>
</li>
</ul>
</li>
<li style="list-style-type: none;">
<label>
<input class="main-item" data-bind ='secondItem' type="checkbox" />Second Item</label>
<ul class="sub-item" style='display: none;'>
<li style="list-style-type: none;">How many items:
<select class="medium" data-bind ='numItems' required>
<option value="">---Select---</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</li>
<li style="list-style-type: none;">
<div data-bind ='items'>
</div>
</li>
</ul>
</li>
</ul>
</script>
Run Code Online (Sandbox Code Playgroud)
查看data-bind我们添加的所有属性?让我们尝试选择那些.
function addItem() {
var thing = new Thing(); // get the data
var el = renderItem(); // get the element
//wiring
el.find("[data-bind=firstItem]").change(function(e){
thing.firstItem = this.checked;
if(thing.firstItem){//show second item
el.find("[data-bind=subItem]").show(); //could be made faster by caching selectors
}else{
el.find("[data-bind=subItem]").hide();
}
});
el.find("[data-bind=subItem] :checkbox").change(function(e){
thing.subItem = this.checked;
});
return {el:el,thing:thing}
}
Run Code Online (Sandbox Code Playgroud)
在这个小提琴中,我们已经为第一个项目和子项目添加了属性,他们已经更新了元素.
让我们继续为第二个属性做同样的事情.它几乎是相同的,直接绑定.在旁注中,有几个库会自动为您执行此操作 - 例如Knockout
这是设置所有绑定的另一个小提琴,这结束了我们的表示层,我们的数据层及其绑定.
var template;
function Thing() { //we use this as an object constructor.
this.firstItem = false;
this.subItem = false;
this.secondItem = false;
this.numItems = 0;
this.items = []; // empty list of items
}
function renderItem() {
template = template || $("[data-template=item]").html();
var el = $("<div></div>").html(template);
return el; // a new element with the template
}
function addItem() {
var thing = new Thing(); // get the data
var el = renderItem(); // get the element
el.find("[data-bind=firstItem]").change(function (e) {
thing.firstItem = this.checked;
if (thing.firstItem) { //show second item
el.find("[data-bind=subItem]").show(); //could be made faster by caching selectors
} else {
el.find("[data-bind=subItem]").hide();
}
});
el.find("[data-bind=subItem] :checkbox").change(function (e) {
thing.subItem = this.checked;
});
el.find("[data-bind=secondItem]").change(function (e) {
thing.secondItem = this.checked;
if (thing.secondItem) {
el.find("[data-bind=detailsView]").show();
} else {
el.find("[data-bind=detailsView]").hide();
}
});
var $selectItemTemplate = el.find("[data-bind=items]").html();
el.find("[data-bind=items]").empty();
el.find("[data-bind=numItems]").change(function (e) {
thing.numItems = +this.value;
console.log(thing.items);
if (thing.items.length < thing.numItems) {
for (var i = thing.items.length; i < thing.numItems; i++) {
thing.items.push("initial"); // nothing yet
}
}
thing.items.length = thing.numItems;
console.log(thing.items);
el.find("[data-bind=items]").empty(); // remove old items, rebind
thing.items.forEach(function(item,i){
var container = $("<div></div>").html($selectItemTemplate.replace("{number}",i+1));
var select = container.find("select");
select.change(function(e){
thing.items[i] = this.value;
});
select.val(item);
el.find("[data-bind=items]").append(container);
})
});
return {
el: el,
thing: thing
}
}
for (var i = 0; i < 3; i++) {
var item = addItem();
window.item = item;
$("body").append(item.el);
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,现在我们完成了繁琐的部分,按钮是一块蛋糕.
我们添加"添加"按钮
<input type='button' value='add' data-action='add' />
Run Code Online (Sandbox Code Playgroud)
和JavaScript:
var stuff = [];
$("[data-action='add']").click(function(e){
var item = addItem();
$("body").append(item.el);
stuff.push(item);
});
Run Code Online (Sandbox Code Playgroud)
男孩,这很容易.
好的,所以删除应该很难,对吧?
HTML:
<input type='button' value='remove' data-action='remove' />
Run Code Online (Sandbox Code Playgroud)
JS:
$("[data-action='remove']").click(function(e){
var item = stuff.pop()
item.el.remove();
});
Run Code Online (Sandbox Code Playgroud)
好的,所以这很可爱.那么我们如何获取数据呢?让我们创建一个按钮,显示屏幕上的所有项目?
<input type='button' value='show' data-action='alertData' />
Run Code Online (Sandbox Code Playgroud)
和JS
$("[data-action='alertData']").click(function(e){
var things = stuff.map(function(el){ return el.thing;});
alert(JSON.stringify(things));
});
Run Code Online (Sandbox Code Playgroud)
哇!我们在模型层中实际表示了我们的数据.我们可以做任何我们想要的东西,这很可爱.
如果我想将其作为表单提交,该怎么办?$.param救援.
<input type='button' value='formData' data-action='asFormData' />
Run Code Online (Sandbox Code Playgroud)
和JS:
$("[data-action='asFormData']").click(function(e){
var things = stuff.map(function(el){ return el.thing;});
alert($.param({data:things}));
});
Run Code Online (Sandbox Code Playgroud)
而且虽然这种格式不是很好看它的东西,PHP(或任何其他流行的技术)将在服务器端欣然读取.