我正在尝试动态创建表单。我应该categories
,subcategories
和questions
。这是一个简单的示例,我将动态添加问题元素:
var i = 1; // to hold increment
$('#add').click(function() {
var p = $(this).closest('p'),
i = $(p).length;
$(p).before('<p> <label> Question ' + i + ': <input type="text" id="question_' + i + '"> </label> </p>');
return false;
});
$('#del').click(function() {
$("p label").last().remove();
i -= 1;
return false;
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<div>
<p> <label> Question 1: <input type="text" id="question_1"> </label> </p>
<p> <a href="#" id="add"> Add Question </a> </p>
<p> <a href="#" id="del"> Del Question </a> </p>
</div>
&#13;
如何添加categories
,以便category
可以包含多个subcategories
,而这些subcategories
也可以包含Test Form
Investment // a category
Real Estate // a subcategory
How much was spent ? // a question
What is the time frame ? // a question
Automobiles // a subcategory
How many vehicles ? // a question
What is the total? // a question
Charity // a category
How much was spent ? // a question
Donations // a subcategory
When started ? // a question
Other // a subcategory
What is the timeframe ? // a question
。每个类别也应该能够包含问题。所以我的表单看起来像这样:
{{1}}
我目前的代码只会产生问题。我试图创建类别,但陷入了递归错误。我试着阅读jtree API,但我不确定它是我需要的。我还试图找到一个允许创建这样一个表单的网站,以便我可以看看他们的JavaScript,但找不到这样的网站。有人可以帮我理解如何实现这个目标吗?
答案 0 :(得分:3)
编辑:交付第二个原型。
答案实际上取决于你正在创造的动态&#34;,我不清楚。因为在我为代表提供有用的答案之前,我不允许要求澄清,所以这里有一个jscript做了一些有用的事情,就像你说的一样。
如果我自己真的这样做,我会整合一个XML文件并完全从JSON或其他东西生成html。或者至少从js填充初始页面。你在这里看到的解决方案非常邋and,并将html紧密地耦合到js。
http://jsfiddle.net/P8X3B/109/(原型问题加法器,其他控件存在,未实现)
新:http://jsfiddle.net/y29vc5k0/28/(原型问题和类别加法器)
/**
***
* questions and categories example
* by Jason D'Aquila
* 23 Jan 2015
* created as prototype of answer to stackoverflow question posted at: http://stackoverflow.com/questions/27772009/
*
* relies on at least jQuery 1.4 ; browsers supporting getter definitions with Object.defineProperty
*/
/* GLOBAL */
function cleaner(text) {
var s = text.replace(/(<|>)/g, '\\$1')
.replace(/ /g, '_')
.replace(/[!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, '');
return s; //can't split a return line
}
/* injective function jQuery objs => String; compact output
* not actually achieved, but this function isn't called in this program anyway
*/
function injectJQueryObjToStr(jqueryObj) {
return ("" + jqueryObj.length) + jqueryObj.attr("id") ? " id: " + jqueryObj.attr("id") : jqueryObj;
//can definitely improve this function
}
canon = ({
/* contract: No enumerable property of canon has the name of an html tag
*/
outputField: $('#out'),
categoriesList: $('#categories'),
/* cannot actually canonize this; see below */
//questionsDropdown: (function () { //references must be invocations ofc
// return $('#questions_del');
//}),
init: function (undef) {
//* //single slash comment toggle
//this.questionsDropDown = (function(nothing) {return nothing;}());
Object.defineProperty(this, "questionsDropdown", {
//cannot actually canonize this
//a setter is only way to "store" a function lookup used with variable access syntax
configurable: true,
enumerable: true,
get: function () {
return $('#questions_del');
}
});
//*/
this.init = undef;
return this;
}
}).init(); //self-initializing object canon
/* CLOSURES */
/* referencing contexts:
* A -- the anonymous function in $('#add') .click
* B -- the anonymous function in $('#cat') .click
*/
//referred by: A, B
var addCategoryIfNotExists = function (desiredName) {
var category_in = desiredName;
var f = cleaner;
//var FF = _compose_ function(x){return 'cat_'+x; } @ cleaner
if ($('#cat_' + f(category_in)).length) {
return $('#cat_' + f(category_in));
} else {
$("<p></p>").attr({
id: 'cat_' + f(category_in)
}).html('<label class="cat_' + f(category_in) + '">' + f(category_in) + '</label>').prependTo(canon.outputField);
//another option is .clone()
canon.categoriesList.append($('<option value="' + f(category_in) + '" />'));
return $('#cat_' + f(category_in));
}
};
function inputFieldAt(locale) {
//return $('input', $(locale).closest('p'));
return $(locale).closest('p').find('input');
}
//consts
var QUESTION_PARENT_ELEMENT_TYPE = "p"; //ideally a preprocessor subs this
/* /CLOSURES */
$('#add').click(
//create closure for i=question #
(function () {
var i = 1;
return function () {
var qid, qidlitl;
var category_input;
i = i + 1;
qidlitl = 'question_' + i;
qid = '"question_' + i + '"'; //quotes for HTML attr setting
var category_el;
//* //single-slash comment toggle
//category_input = $('input', $(this).closest('p')).val();
category_input = inputFieldAt(this).val();
category_el = addCategoryIfNotExists(category_input);
//check category_el === canon.outputField.find('#' + 'cat_' + cleaner(category_input) )
/*/
category_el = document.getElementById("out");
//*/
$('<' + QUESTION_PARENT_ELEMENT_TYPE + '></' + QUESTION_PARENT_ELEMENT_TYPE + '>').html('<label for=' + qid + '> Question ' + i + ': </label><input type="text" id=' + qid + '>').appendTo(category_el);
$("<option></option>").attr({
"class": "questions_options",
value: qidlitl
}).text('Question ' + i + '').appendTo(canon.questionsDropdown);
return false; //callback contract
};
})() //SIF to get closure for i = 1 + number of questions ever generated
); //$('#add').click
$('#del').click(function () {
var qselect = canon.questionsDropdown[0]; //This [0] is the inelegance of mixing frameworks
$('#' + qselect.options[qselect.selectedIndex].value + '')
.closest(QUESTION_PARENT_ELEMENT_TYPE).remove();
qselect.remove(qselect.selectedIndex);
return false;
});
$('#cat').click(function () {
//add category and return false exit signal unless add_category returned literal not false (i.e. true)
var category_input;
//category_input = $('input', $(this).closest('p')).val();
category_input = inputFieldAt(this).val();
var res = addCategoryIfNotExists(category_input);
//return !!(res && (res === true)); //!! might get eliminated by compiler?
return res && (res === true) ? true : false; //equality < logical AND < ternary
});
//EOF
html稍有改动。见jsfiddle。
所以,几周后,我了解到你实际上无法规范化大多数DOM查找或jqueries。这是一个有类别和问题的jsfiddle。下一个原型将具有子类别,最终答案将允许您删除没有子类别或问题的类别和子类别。
这个jscript中有一个谜。当您添加问题时,它们会出现在html中的问题之前,即使在包含&lt; \ p&gt;的情况下使用$ .appendTo()也是如此。
答案 1 :(得分:3)
我设计这个的方法是在JS中使用一个名为"category"
的类(通过使用constrcutor函数),这样它可以在其自身中包含其他"categories"
,也许在数组中。我会让这个类还包含一个questions
数组。现在,在不考虑html的情况下,我对世界的外观有一个很好的清晰模型。在下一步中,我将编写一个函数,可以使用其中一个category
实例并生成dom。这个函数drawCategory
将使用一个辅助函数,它可能是JS中的一个内部函数,它知道如何为不包含任何类别的类别生成dom(换言之,叶子节点),drawCategory
智能地使用该辅助函数并返回单个类别实例的整个dom。接下来,我简单地迭代我拥有的类别实例的数量,并继续将类别实例传递给drawCategory
,它自动执行正确的操作并每次返回正确的dom。为了避免多个dom更新,我只需为每个类别生成dom,将其保存在某处,只需构建一次整个dom并将其附加到某个目标元素。