(function(){ "use strict"; angular .module("app.utils") .directive("formValidator", formValidator); function formValidator($translate){ return { restrict: "E", scope: { handler: "=" }, link: function(scope, el, attrs){ var options = { // Password length. If less - field won't be a valid. "PasswordLength": get(attrs.passwordLength) || 8, // Show\hide interactive errors on UI. "DisplayErrors": get(attrs.displayErrors), "DefaultImage": attrs.defaultImage, // Emails #ids collection to compare. "Email": get(attrs.email) || false, // // Phones #ids collection which will be used for validation. // "Phone": get(attrs.phone) || false, "Phone": get(attrs.phone) || false, // Passwords #ids collection to compare (length, equal, empty). "ComparePassword": get(attrs.comparePassword) || false, // Retrieve input ids for generating the validation rules. "Set": get(attrs.set), "USASet": get(attrs.usaSet), "SetSelectOptionById": get(attrs.setSelectOptionById), "SetUSASelectOptionById": get(attrs.setUSASelectOptionById), "SetSelectOptionByClass": get(attrs.setSelectOptionByClass), "CountryId": get(attrs.countryId), "Excluded": get(attrs.excluded), "LicenseDocuments": get(attrs.licenseDocuments), "Photo": attrs.photo, // A border type depending on event happened. "Border": { "Default": "1px solid #ccc" || attrs.defaultBorder, "Danger": "2px solid #aa0000" || attrs.dangerBorder }, // #id or .class element which will manage current behaviour. "Element": attrs.element, // Procedure which will be invoked through directive scope (if validation result is successful). "Handler": attrs.handler }; try { var result = $("#" + options.Element).length || $("." + options.Element).length; if (!result) throw "Can't bind validation to non-existent entity. Be sure, that you had specified element #id or .class as a parameter into 'element' attribute."; } catch (e) { throw new Error(e); } var element = $("#" + options.Element) || $("." + options.Element); element.bind("click", function($event){ extendArray( [options.Email, options.Phone, options.ComparePassword] , options.Set); var validation = []; var option = $("#"+options.CountryId+" option:selected")[0]; var lang = null; if(option){ lang = $(option).attr('lang'); } if(lang == "US"){ validation = [ isValid([{ Type: 'Null', Collection: options.USASet} ]) ]; }else{ validation = [ isValid([{ Type: 'Null', Collection: options.Set} ]) ]; } options.ComparePassword && validation.push( isValid([{ Type: 'Password', Collection: options.ComparePassword }])); options.Email && validation.push( isValid([{ Type: 'Email', Collection: options.Email }])); options.Phone && validation.push( isValid([{ Type: 'Phone', Collection: options.Phone }])); if(lang == "US"){ options.SetUSASelectOptionById && validation.push( isValid([{ Type: 'EmptySelectOptionById', Collection: options.SetUSASelectOptionById }])); }else{ options.SetSelectOptionById && validation.push( isValid([{ Type: 'EmptySelectOptionById', Collection: options.SetSelectOptionById }])); } options.SetSelectOptionByClass && validation.push( isValid([{ Type: 'EmptySelectOptionByClass', Collection: options.SetSelectOptionByClass }])); options.Photo && validation.push( isValid([{ Type: 'Photo', Collection: options.Photo }])); options.Excluded && validation.push( isValid([{ Type: 'Excluded', Collection: options.Excluded }])); options.LicenseDocuments && validation.push( isValid([{ Type: 'LicenseDocuments', Collection: options.LicenseDocuments }])); options.DisplayErrors && displayErrors(validation); isPassed(validation) && scope.handler(); }); scope._options = options; scope.isDynamic = function(){ if (options.IsDynamic) { element.trigger("click"); } }; /* ** FORM VALIDATION METHODS */ function isValid(validationRules){ var validation = { IsEmailInCollection: IsEmailInCollection, IsNullInCollection: IsNullInCollection, IsPasswordInCollection: IsPasswordInCollection, IsPhoneInCollection:IsPhoneInCollection, IsEmptySelectOptionByIdInCollection:IsEmptySelectOptionByIdInCollection, IsEmptySelectOptionByClassInCollection:IsEmptySelectOptionByClassInCollection, IsPhotoInCollection:IsPhotoInCollection, IsExcludedInCollection:IsExcludedInCollection, IsLicenseDocumentsInCollection:IsLicenseDocumentsInCollection, }, response = false; validationRules.forEach(function(rule){ var method = "Is" + rule.Type + "InCollection"; response = validation[method](rule.Collection); }); return response; } function displayErrors(collection){ collection.forEach(function(v){ if (collection.find(function(val){ return v.Type == val.Type && val.State == false; })) { $("#error-validation-block-" + v.Type).show(); } else { $("#error-validation-block-" + v.Type).hide(); } }); } function isPassed(collection){ return collection.every(function(v){ return v.State == true }) } function IsEmailInCollection(collection) { var status = true; collection.forEach(function(i){ var ui = $('#'+i); var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var result = re.test(ui.val()); if (!result) { status = false; renderNegativeBorder(ui); } else { renderPositiveBorder(ui); } renderFocusBorder(ui); }); return {Type: "email", State: status}; } function IsExcludedInCollection(collection){ var result = true; collection.forEach(function(i){ var element = $('#'+i.element); var border = $('#'+i.border); if (element.length) { result = false; renderNegativeBorder(border); } else { renderPositiveBorder(border); } renderFocusBorder(border); }); return {Type: "null", State: result}; } function IsLicenseDocumentsInCollection(obj){ var result = true; var elements = $('.'+obj.class); var border = $('#'+obj.border); if (!elements.length) { result = false; renderNegativeBorder(border); } else { renderPositiveBorder(border); } renderFocusBorder(border); return {Type: "null", State: result}; } function IsPhoneInCollection(collection){ var status = true; collection.forEach(function(i){ var ui = $('#'+i); var re = /^\+([0-9]){9,13}$/; var result = re.test(ui.val()); if (!result) { status = false; renderNegativeBorder(ui); } else { renderPositiveBorder(ui); } renderFocusBorder(ui); }); return {Type: "phone", State: status}; } function IsNullInCollection(collection){ var result = true; collection.forEach(function(i){ var ui = $('#'+i); if (ui.val() == null || ui.val() == "") { result = false; renderNegativeBorder(ui); } else { renderPositiveBorder(ui); } renderFocusBorder(ui); }); return {Type: "null", State: result}; } function IsPhotoInCollection(photo){ var result = true; var ui = $('#'+photo); if (ui == null || !$(ui).attr('src') || $(ui).attr('src') === options.DefaultImage) { result = false; renderNegativeBorder(ui); } else { renderPositiveBorder(ui); } renderFocusBorder(ui); return {Type: "null", State: result}; } function IsEmptySelectOptionByIdInCollection(collection){ var result = true; collection.forEach(function(i){ var ui = $('[data-id="'+i+'"]'); var selectedOptions = $('#'+i + " option:selected"); if (!isValidSelectOption(selectedOptions)) { result = false; if(ui && ui.length){ renderNegativeBorder(ui); }else{ renderNegativeBorder(selectedOptions); } } else { if(ui && ui.length){ renderPositiveBorder(ui); }else{ renderPositiveBorder(selectedOptions); } } renderFocusBorder(ui); }); return {Type: "null", State: result}; } function IsEmptySelectOptionByClassInCollection(collection){ var result = true; collection.forEach(function(i){ $('.'+i).each(function(index) { var id = $(this).attr('id'); var ui = $(this).parent().find('[data-id="'+id+'"]'); if(id && ui.length){ if (!isValidSelectOption($(this))) { result = false; renderNegativeBorder(ui); } else { renderPositiveBorder(ui); } renderFocusBorder(ui); } }); }); return {Type: "null", State: result}; } function IsPasswordInCollection(collection){ var result = true, p1, p2; p1 = $('#'+ collection[0]); p2 = $('#'+ collection[1]); if (!p1.val() && !p2.val() || p1.val().length < options.PasswordLength || p2.val().length < options.PasswordLength || p1.val() != p2.val()) { result = false; renderNegativeBorder(p1); renderNegativeBorder(p2); } else { renderPositiveBorder(p1); renderPositiveBorder(p2); } renderFocusBorder(p1); renderFocusBorder(p2); return {Type: "password", State: result}; } function renderFocusBorder(ui){ ui.focus(function(){ ui[0].style.border = options.Border.Default; }) } function renderNegativeBorder(ui){ if(ui && ui.length){ ui[0].style.border = options.Border.Danger; } } function renderPositiveBorder(ui){ if(ui && ui.length){ ui[0].style.border = options.Border.Default; } } function isValidSelectOption(uiList){ if(!$(uiList).length){ return false; } var isValid = true; $(uiList).each(function(){ if(!$(this).val()){ isValid = false; } }); return isValid; } }, template: '
' + '' + '' + '' }; /** * Retrieve value from received array and if it equals not false -> take its elements into the main collection. * @param valueCollection {Array} * @param mainArray {Array} */ function extendArray(valueCollection, mainArray){ valueCollection.forEach(function(value){ if (value) { value.forEach(function(el){ mainArray.push(el); }); } }); } /** * Parse serialized string, otherwise just return it. * @param val {String|Boolean|Number|Array|Function} * @returns {*} */ function get(val) { return typeof val == "string" ? JSON.parse(val) : val; } /** * Capitalize first letter in word. * @param string {String} * @returns {string} */ function upperFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } } // IoC container. formValidator.$inject = [ '$translate' ]; })();