tg-form
Version:
Extension for ngForm with powerful validation mechanism
522 lines (429 loc) • 18.5 kB
JavaScript
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
var tgForm = __webpack_require__(1),
tgModel = __webpack_require__(3),
tgFormMessage = __webpack_require__(4),
tgFormValidator = __webpack_require__(5);
angular.module('tg.form', [])
.directive('tgForm', tgForm)
.directive('ngModel', tgModel)
.directive('tgFormMessage', tgFormMessage)
.directive('tgFormValidator', tgFormValidator);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var overrideFn = __webpack_require__(2);
tgForm.$inject = ['$parse', '$timeout'];
function tgForm($parse, $timeout) {
return {
restrict: 'EA',
require: ['form', 'tgForm'],
compile: function () {
function preLink(scope, element, attrs, ctrls) {
var formCtrl = ctrls[0],
tgFormCtrl = ctrls[1],
onSubmit = $parse(attrs.onSubmit);
formCtrl.$isExtendedForm = true;
tgFormCtrl.$form = formCtrl;
formCtrl.submit = function () {
var event = new Event('submit'),
nativeElement = element[0];
/**
* Current angular submit handler:
* var handleFormSubmission = function(event) {
* scope.$apply(function() {
* controller.$commitViewValue();
* controller.$setSubmitted();
* });
*
* event.preventDefault();
* };
*
* Cause this block working in angular context
* and to prevent Error: $digest already in progress
* We've to run this asynchronously
*/
setTimeout(function () {
nativeElement.dispatchEvent(event);
});
};
formCtrl.hasErrorOfType = function (errorType) {
return !!(errorType && formCtrl.$error[errorType]);
};
overrideFn(formCtrl, {
$addControl: function (baseFn, control) {
baseFn();
tgFormCtrl.$$addFormControl(control);
if (control.hasOwnProperty('$parsers') &&
control.hasOwnProperty('$formatters')) {
var validationTrigger = function (value) {
tgFormCtrl.$$validateCustoms(control);
return value;
};
control.$parsers.push(validationTrigger);
control.$formatters.push(validationTrigger);
}
},
$removeControl: function (baseFn, control) {
baseFn();
tgFormCtrl.$$removeFormControl(control);
},
$setSubmitted: function (baseFn) {
if (formCtrl.$$inSubmition) {
return;
}
baseFn();
if (attrs.showErrorsOnSubmit === 'true') {
tgFormCtrl.$$updateFormErrors();
}
if (attrs.submitChildForms === 'true') {
tgFormCtrl.formControls.forEach(function (formControl) {
if (formControl.hasOwnProperty('$setSubmitted') && !formControl.$submitted) {
formCtrl.$$inSubmition = true;
formControl.$setSubmitted();
formCtrl.$$inSubmition = false;
}
});
}
if (formCtrl.$valid) {
onSubmit(scope, {
$form: formCtrl
});
}
}
});
}
return {
pre: preLink
};
},
controller: ['$attrs', function tgFormController(attrs) {
this.formMessages = [];
this.formControls = [];
this.$$addFormMessage = function (formMessage) {
this.formMessages.push(formMessage);
};
this.$$removeFormMessage = function (formMessage) {
var idx = this.formMessages.indexOf(formMessage);
if (idx !== -1) {
this.formMessages.splice(idx, 1);
}
};
this.$$addFormControl = function (formControl) {
this.formControls.push(formControl);
};
this.$$removeFormControl = function (formControl) {
var idx = this.formControls.indexOf(formControl);
if (idx !== -1) {
this.formControls.splice(idx, 1);
}
};
this.$$validateCustoms = function (excluded) {
var self = this;
if (!Array.isArray(excluded)) {
excluded = [excluded];
}
$timeout(function () {
self.formControls.forEach(function (ngModelCtrl) {
if (ngModelCtrl.hasOwnProperty('$hasCustomValidations') &&
excluded.indexOf(ngModelCtrl) === -1) {
ngModelCtrl.$validate();
}
});
self.$$updateFormErrors();
});
};
this.$$updateFormErrors = function () {
var self = this;
self.formMessages.forEach(function (formMessage) {
formMessage.setMessage(null);
});
var fUpdateFormErrorsFor = function (formCtrl) {
if (attrs.showErrorsOnSubmit !== 'true' || formCtrl.$submitted) {
for (var validationKey in formCtrl.$error) {
if (formCtrl.$error.hasOwnProperty(validationKey)) {
var controls = formCtrl.$error[validationKey];
if (!Array.isArray(controls)) {
controls = [controls];
}
controls.forEach(function (control) {
if (control.hasOwnProperty('$submitted')) {
if (!control.$isExtendedForm) {
fUpdateFormErrorsFor(control);
}
}
else if (control.$invalid) {
self.formMessages.forEach(function (formMessage) {
if (control.$name === formMessage.name ||
(formMessage.isFormMessage && control.$isFormValidator)) {
if (!formMessage.getMessage()) {
formMessage.setMessageByKey(validationKey);
}
}
});
}
});
}
}
}
};
fUpdateFormErrorsFor(self.$form);
};
this.$$updateControlErrors = function (ngModelCtrl) {
var self = this;
if (ngModelCtrl.$invalid) {
if (attrs.showErrorsOnSubmit !== 'true' || self.$form.$submitted) {
for (var validationKey in ngModelCtrl.$error) {
if (ngModelCtrl.$error.hasOwnProperty(validationKey) &&
ngModelCtrl.$error[validationKey]) {
self.formMessages.forEach(function (formMessage) {
if ((ngModelCtrl.$name === formMessage.name) ||
(formMessage.isFormMessage && ngModelCtrl.$isFormValidator)) {
if (!formMessage.getMessage()) {
formMessage.setMessageByKey(validationKey);
}
}
});
}
}
}
}
};
}]
};
}
module.exports = tgForm;
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;function overrideFn(context, fnName, fn) {
if (typeof fnName === 'string') {
return overrideFnInternal(context, fnName, fn);
} else {
var obj = arguments[1],
keys = Object.keys(obj);
return keys.reduce(function (result, key) {
result[key] = overrideFnInternal(context, key, obj[key]);
return result;
}, {});
}
function overrideFnInternal(context, fnName, fn) {
var baseFn = context[fnName] || function () {};
context[fnName] = function overrideFunction() {
var args = arguments,
params = Array.prototype.slice.call(args),
isCalledLikeConstructor = this instanceof overrideFunction;
params.unshift(function () {
var _args = arguments.length ? arguments : args,
_params = Array.prototype.slice.call(_args);
if (isCalledLikeConstructor) {
_params.unshift(this);
return new (Function.prototype.bind.apply(baseFn, _params));
}
return baseFn.apply(this, _params);
}.bind(this));
return fn.apply(this, params);
};
try {
Object.defineProperties(context[fnName], {
length: {
get: function () {
return baseFn.length;
}
},
name: {
get: function () {
return baseFn.name;
}
}
});
}
catch (ex) {
console.warn(ex);
}
context[fnName].toString = function () {
return baseFn.toString();
};
return baseFn;
}
}
if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = overrideFn;
} else if (true) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
return overrideFn;
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
}
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
var overrideFn = __webpack_require__(2);
tgModel.$inject = ['$q'];
function tgModel($q) {
return {
restrict: 'EA',
require: ['ngModel', '^?tgForm'],
compile: function () {
function getValidationKey(str, prefix) {
var validationKey = str.substring(prefix.length);
return validationKey.charAt(0).toLowerCase() + validationKey.slice(1);
}
function preLink(scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0],
tgFormCtrl = ctrls[1],
tgValidateStr = 'tgValidate',
tgValidateAsyncStr = 'tgValidateAsync';
if (!tgFormCtrl) {
return false;
}
if (ngModelCtrl.$name.indexOf('form-validator') === 0) {
ngModelCtrl.$isFormValidator = true;
}
for (var prop in attrs) {
if (attrs.hasOwnProperty(prop)) {
var idx = prop.indexOf(tgValidateStr);
if (idx === 0) {
ngModelCtrl.$hasCustomValidations = true;
var validationFn = attrs[prop],
isAsync = prop.indexOf(tgValidateAsyncStr) === 0,
validators = isAsync ? ngModelCtrl.$asyncValidators : ngModelCtrl.$validators,
validationKey = getValidationKey(prop, isAsync ? tgValidateAsyncStr : tgValidateStr);
validators[validationKey] = function (isAsync, validationFn, modelValue, viewValue) {
var result = scope.$eval(validationFn, {
$form: tgFormCtrl,
$value: viewValue,
$model: modelValue
});
if (isAsync) {
// result is not promise
if (!(result && result.then)) {
result = (result) ? $q.resolve(result) : $q.reject(result);
}
} else {
// convert result to boolean
result = !!result;
}
return result;
}.bind(null, isAsync, validationFn);
}
}
}
overrideFn(ngModelCtrl, '$$runValidators', function (baseFn, modelValue, viewValue, doneCallback) {
baseFn(modelValue, viewValue, function (allValid) {
doneCallback(allValid);
if (!allValid) {
tgFormCtrl.$$updateControlErrors(ngModelCtrl);
}
});
});
}
return {
pre: preLink
};
}
};
}
module.exports = tgModel;
/***/ },
/* 4 */
/***/ function(module, exports) {
tgFormMessage.$inject = [];
function tgFormMessage() {
return {
restrict: 'EA',
require: '^tgForm',
scope: true,
template: '<span class="form-message">{{message}}</span>',
compile: function () {
function preLink(scope, element, attrs, tgFormCtrl) {
var inst = {
name: attrs.name || '@',
isFormMessage: (!attrs.name),
setMessageByKey: function (key) {
if (key) {
key = key + 'Message';
if (attrs.hasOwnProperty(key)) {
var msg = scope.$parent.$eval(attrs[key]);
this.setMessage(msg);
}
}
},
setMessage: function (message) {
scope.message = message;
},
getMessage: function () {
return scope.message;
}
};
tgFormCtrl.$$addFormMessage(inst);
scope.$on('$destroy', function () {
tgFormCtrl.$$removeFormMessage(inst);
});
}
return {
pre: preLink
};
}
};
}
module.exports = tgFormMessage;
/***/ },
/* 5 */
/***/ function(module, exports) {
tgFormValidator.$inject = [];
function tgFormValidator() {
return {
restrict: 'EA',
require: '^tgForm',
scope: true,
template: '<input type="hidden" ng-model="__validator" name="form-validator-{{$id}}">',
replace: true
};
}
module.exports = tgFormValidator;
/***/ }
/******/ ]);
//# sourceMappingURL=tg-form.js.map