我正在尝试动态创建一个表单。我应该有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;
});
<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>
如何添加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
我当前的代码只会产生问题。我尝试创建类别,但遇到了递归错误。我试图阅读jtree API,但我不确定它是否是我需要的。我还试图找到一个允许创建这样一个表单的网站,以便我可以查看他们的 JavaScript,但找不到这样的网站。有人可以帮助我了解如何实现这一目标吗?
我设计它的方法是在 JS 中有一个名为 "category"
的类(通过使用 constrcutor 函数),这样它就可以包含其他"categories"
本身,也许在一个数组中。我会让这个类也包含一个questions
数组。现在,不用过多地考虑html,我有一个关于世界样子的漂亮而清晰的模型。在下一步中,我将编写一个函数,该函数可以采用这些category
实例之一并生成 dom。此函数drawCategory
将使用一个辅助函数,该函数可能是 JS 中的一个内部函数,该函数知道如何为不包含任何类别(换句话说是叶节点)的类别生成 dom,drawCategory
智能地使用该辅助函数并返回单个类别实例的整个 dom。接下来,我只是遍历我有多少个类别实例,并不断将类别实例传递给drawCategory
它会自动执行正确的操作并每次返回正确的 dom。为了避免多次 dom 更新,我只会为每个类别生成 dom,将其保存在某个地方,只构建一次整个 dom 并将其附加到某个目标元素。
编辑:第二个原型交付。
答案实际上取决于您"动态"创建的内容,我不清楚。 由于在我为 rep 提供有用的答案之前,我不允许要求澄清,这里有一个 jscript 可以做一些有用的事情,就像你所说的那样。
如果我真的自己这样做了,我会集成一个XML文件并完全从JSON或其他东西生成html。 或者至少从 js 填充初始页面。 你在这里看到的解决方案非常草率,并且将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 查找或 jquery。 这是一个带有类别和问题的 jsfiddle。 下一个原型将具有子类别,最终答案将允许您删除没有子类别或问题的类别和子类别。
这个jscript对我来说是一个谜。 当您添加问题时,它们会出现在 html 中的问题之前,即使 $.appendTo() 用于包含的 <\p> 。