我正在尝试使用jQuery构建一个自制的验证器。我认为我在jQuery中发现了一个限制:当将jQuery值赋给json变量时,然后使用jQuery将更多DOM元素添加到适合变量查询的当前页面,似乎没有办法访问这些DOM添加到页面的元素符合json变量的查询。
请考虑以下代码:
var add_form = {
$name_label: $("#add-form Label[for='Name']"),
$name: $("#add-form #Name"),
$description_label: $("#add-form Label[for='Description']"),
$description: $("#add-form #Description"),
$submit_button: $("#add-form input#Add"),
$errors: $("#add-form .error"),
error_marker: "<span class='error'> *</span>"
}
function ValidateForm() {
var isValid = true;
add_form.$errors.remove();
if (add_form.$name.val().length < 1 ) {
add_form.$name_label.after(add_form.error_marker);
isValid = false;
}
if (add_form.$description.val().length < 1) {
add_form.$description_label.after(add_form.error_marker);
isValid = false;
}
return isValid
}
$(function(){
add_form.$submit_button.live("click", function(e){
e.preventDefault();
if(ValidateForm())
{
//ajax form submission...
}
});
})
这里有一个例子:http://jsfiddle.net/Macxj/3/
首先,我创建一个json变量来表示html add表单。然后,我创建一个函数来验证表单。最后,我将表单的提交按钮的click事件绑定到验证表单。
请注意,我正在使用jQuery after()方法在表单中的每个无效字段标签后放置一个包含'*'的span。另请注意,在重新验证之前,我正在从表单中清除先前提交尝试的星号(这是失败的原因)。
显然,调用add_form。$ errors.remove();不起作用,因为$ errors变量仅指向在创建时匹配其查询的DOM元素。在那个时间点,没有标签带有error_marker变量的后缀。
因此,jQuery变量在尝试删除它时不识别它的查询的匹配元素,因为它们在首次分配变量时不存在。如果一个jQuery变量HAD AN eval() METHOD会重新评估其包含的查询以查看是否有任何新的DOM元素匹配它,那将是很好的。但是唉...
有什么建议吗?
提前致谢!
答案 0 :(得分:8)
jQuery对象不是“实时”是正确的 - 也就是说,jQuery对象中的元素集不会动态更新。 (这是件好事。)
如果您确实想要更新任意jQuery对象,可以从.selector
获取用于创建对象的选择器:
var els = $('#form input');
els.selector // '#form input'
所以你可以els = $(els.selector);
重新查询DOM。
但是,请注意,如果您在初始选择器之后修改了集合(add
,filter
,children
等函数),或者jQuery对象是在没有创建的情况下创建的使用选择器(通过传递DOMElement
),然后.selector
几乎没用,因为选择器将为空,不正确甚至可能无效。
更好的方法是重构您的代码,使您不会持久化jQuery对象;其他答案提出了一些很好的建议。
此外,请确保您也在验证输入服务器端!
答案 1 :(得分:7)
对于要更改的对象,不要使JSON对象引用静态值,而是将其设为函数:
$errors: function() { return $("#add-form .error"); },
因为它是一个函数,所以每次调用add_form.$errors()
时它都会重新评估错误字段。
答案 2 :(得分:4)
您解决问题的方法存在许多结构性问题:
避免使用全局变量
您正在验证的页面上可能并不总是只有一个表单。如果有一天你会决定你有几种形式怎么办?您的add_form
变量是全局变量,因此会发生冲突。
请勿使用提交按钮点击事件来检测表单提交。
如果通过js调用$("form").submit();
或输入密钥提交表单怎么办?
如果您不确定在配置对象创建时对象是否已存在,请存储选择器而不是DOM对象。
.live
已弃用。请改用.on
。
它将解决您的实际问题,但我强烈建议解决所有4个问题。
对于2,附加验证器的最佳位置不在提交按钮上,而是在表单的提交事件上。像这样:
$("#add-form").submit(function(event) {
event.preventDefault();
if (validateForm(this))
$.ajax({
url: $(this).attr("action"),
data: $(this).serialize(),
//ETC
});
});
请注意表单现在也更容易访问。您的配置对象不再需要存储对提交按钮的引用。
您的配置对象现在可以简化为:
{
name_label: "Label[for='Name']",
name: "#Name",
description_label: "Label[for='Description']",
description: "#Description",
errors: ".error",
error_marker: "<span class='error'> *</span>"
}
在validateForm中,您可以按如下方式使用这些选择器:
var $name_label = $(configuration.name_label, this); //Finds the label within the current form.
现在,为每个表单允许不同的配置参数使用如下:
function enableValidation(form, configuration) {
$.extend(configuration, {
//Default configuration parameters here.
});
function validateForm(form) {
//Your original function here with modifications.
}
$(form).submit(funciton(e) {
if (!validateForm(this))
e.preventDefault();
});
}
function enableAjax(form) {
$(form).submit(function(e){
if (!e.isDefaultPrevented()) {
e.preventDefault();
$.ajax(...);
}
});
}
$(function() {
enableValidation("#add-form", {/*specialized config parameters here*/});
enableAjax("#add-form");
});