import '../jquery-form/jquery.form.min';
let formCallbacks = {
before: [], success: [], error: []
};
class Form {
constructor(options) {
let _this = this;
_this.options = $.extend({
// 表单的 jquery 对象或者css选择器
form: null,
// 开启表单验证
validate: false,
// 表单错误信息class
errorClass: 'has-error',
// 表单错误信息容器选择器
errorContainerSelector: '.with-errors',
// 表单组css选择器
groupSelector: '.form-group,.form-label-group',
// tab表单css选择器
tabSelector: '.tab-pane',
// 错误信息模板
errorTemplate: '
',
// 保存成功后自动跳转
autoRedirect: false,
// 不允许自动移除表单错误信息
disableAutoRemoveError: false,
// 表单提交之前事件监听,返回false可以中止表单继续提交
before: function () {},
// 表单提交之后事件监听,返回false可以中止后续逻辑
after: function () {},
// 成功事件,返回false可以中止后续逻辑
success: function () {},
// 失败事件,返回false可以中止后续逻辑
error: function () {},
}, options);
_this.originalValues = {};
_this.$form = $(_this.options.form).first();
_this._errColumns = {};
_this.submit();
}
submit() {
let Dcat = window.Dcat,
_this = this,
$form = _this.$form,
options = _this.options,
$submitButton = $form.find(':submit');
// 移除所有错误信息
_this.removeErrors();
$form.ajaxSubmit({
beforeSubmit: function (fields, form, _opt) {
if (options.before(fields, form, _opt, _this) === false) {
return false;
}
// 触发全局事件
if (fire(formCallbacks.before, fields, form, _opt, _this) === false) {
return false;
}
// 开启表单验证
if (options.validate) {
$form.validator('validate');
if ($form.find('.' + options.errorClass).length > 0) {
return false;
}
}
$submitButton.buttonLoading();
},
success: function (response) {
$submitButton.buttonLoading(false);
if (options.after(true, response, _this) === false) {
return;
}
if (options.success(response, _this) === false) {
return;
}
if (fire(formCallbacks.success, response, _this) === false) {
return;
}
if (! response.status) {
Dcat.error(response.message || 'Save failed!');
return;
}
Dcat.success(response.message || 'Save succeeded!');
if (response.redirect === false) {
return;
}
if (response.redirect) {
return Dcat.reload(response.redirect);
}
if (options.autoRedirect) {
history.back(-1);
}
},
error: function (response) {
$submitButton.buttonLoading(false);
if (options.after(false, response, _this) === false) {
return;
}
if (options.error(response, _this) === false) {
return;
}
if (fire(formCallbacks.error, response, _this) === false) {
return;
}
try {
var error = JSON.parse(response.responseText),
key;
if (response.status != 422 || ! error || ! Dcat.helpers.isset(error, 'errors')) {
return Dcat.error(response.status + ' ' + response.statusText);
}
error = error.errors;
for (key in error) {
// 显示错误信息
_this._errColumns[key] = _this.showError($form, key, error[key]);
}
} catch (e) {
return Dcat.error(response.status + ' ' + response.statusText);
}
}
});
}
// 显示错误信息
showError($form, column, errors) {
let _this = this,
$field = _this.queryFieldByName($form, column),
render = function (msg) {
$group.find(_this.options.errorContainerSelector).first().append(
_this.options.errorTemplate.replace('{message}', msg)
);
};
queryTabTitleError(_this, $field).removeClass('d-none');
// 保存字段原始数据
_this.originalValues[column] = _this.getFieldValue($field);
if (! $field) {
if (Dcat.helpers.len(errors) && errors.length) {
Dcat.error(errors.join(" \n "));
}
return;
}
let $group = $field.closest(_this.options.groupSelector), j;
$group.addClass(_this.options.errorClass);
if (typeof errors === 'string') {
render(errors)
} else {
for (j in errors) {
render(errors[j])
}
}
if (! _this.options.disableAutoRemoveError) {
removeErrorWhenValChanged(_this, $field, column);
}
return $field;
}
// 获取字段值
getFieldValue($field) {
let vals = [],
type = $field.attr('type'),
checker = type === 'checkbox' || type === 'radio',
i;
for (i = 0; i < $field.length; i++) {
if (checker) {
vals.push($($field[i]).prop('checked'));
continue;
}
vals.push($($field[i]).val());
}
return vals;
}
// 判断值是否改变
isValueChanged($field, column) {
return ! Dcat.helpers.equal(this.originalValues[column], this.getFieldValue($field));
}
// 获取字段jq对象
queryFieldByName($form, column) {
if (column.indexOf('.') !== -1) {
column = column.split('.');
let first = column.shift(),
i,
sub = '';
for (i in column) {
sub += '[' + column[i] + ']';
}
column = first + sub;
}
var $c = $form.find('[name="' + column + '"]');
if (!$c.length) $c = $form.find('[name="' + column + '[]"]');
if (!$c.length) {
$c = $form.find('[name="' + column.replace(/start$/, '') + '"]');
}
if (!$c.length) {
$c = $form.find('[name="' + column.replace(/end$/, '') + '"]');
}
if (!$c.length) {
$c = $form.find('[name="' + column.replace(/start\]$/, ']') + '"]');
}
if (!$c.length) {
$c = $form.find('[name="' + column.replace(/end\]$/, ']') + '"]');
}
return $c;
}
// 移除给定字段的错误信息
removeError($field, column) {
let parent = $field.parents(this.options.groupSelector),
errorClass = this.options.errorClass;
parent.removeClass(errorClass);
parent.find('error').html('');
// tab页下没有错误信息了,隐藏title的错误图标
let tab;
if (! queryTabByField(this, $field).find('.'+errorClass).length) {
tab = queryTabTitleError(this, $field);
if (! tab.hasClass('d-none')) {
tab.addClass('d-none');
}
}
delete this._errColumns[column];
}
// 删除所有错误信息
removeErrors() {
let _this = this,
column,
tab;
// 移除所有字段的错误信息
_this.$form.find(_this.options.errorContainerSelector).each(function (_, $err) {
$($err).parents(_this.options.groupSelector).removeClass(_this.options.errorClass);
$($err).html('');
});
// 移除tab表单tab标题错误信息
for (column in _this._errColumns) {
tab = queryTabTitleError(_this._errColumns[column]);
if (! tab.hasClass('d-none')) {
tab.addClass('d-none');
}
}
// 重置
_this._errColumns = {};
}
}
// 监听表单提交事件
Form.submitting = function (callback) {
typeof callback == 'function' && (formCallbacks.before.push(callback));
return this
};
// 监听表单提交完毕事件
Form.submitted = function (success, error) {
typeof success == 'function' && (formCallbacks.success.push(success));
typeof error == 'function' && (formCallbacks.error.push(error));
return this
};
// 当字段值变化时移除错误信息
function removeErrorWhenValChanged(form, $field, column) {
let _this = form,
removeError = function () {
_this.removeError($field, column)
};
$field.one('change', removeError);
$field.off('blur', removeError).on('blur', function () {
if (_this.isValueChanged($field, column)) {
removeError();
}
});
// 表单值发生变化就移除错误信息
function handle() {
setTimeout(function () {
if (! $field.length) {
return;
}
if (_this.isValueChanged($field, column)) {
return removeError();
}
handle();
}, 500);
}
handle();
}
function getTabId(form, $field) {
return $field.parents(form.options.tabSelector).attr('id');
}
function queryTabByField(form, $field)
{
let id = getTabId(form, $field);
if (! id) {
return $('');
}
return $('#' + id);
}
function queryTabTitleError(form, $field) {
return queryTabByField(form, $field).find('.text-danger');
}
// 触发钩子事件
function fire(callbacks) {
let i, j,
result,
args = arguments,
argsArr = [];
delete args[0];
args = args || [];
for (j in args) {
argsArr.push(args[j]);
}
for (i in callbacks) {
result = callbacks[i].apply(callbacks[i], argsArr);
if (result === false) {
return result; // 返回 false 会代码阻止继续执行
}
}
}
// 开启form表单模式
$.fn.form = function (options) {
let $this = $(this);
options = $.extend(options, {
form: $this,
});
$this.find(':submit').click(function (e) {
Dcat.Form(options);
return false;
});
};
export default Form