/********************************************* * Copyright (c) 2013 AnsibleWorks, Inc. * * FormGenerator * Pass in a form definition from FormDefinitions and out pops an html template. * See js/form-definitions.js for form example. For now produces a Twitter Bootstrap * horizontal form. * */ angular.module('FormGenerator', ['GeneratorHelpers']) .factory('GenerateForm', [ '$compile', 'SearchWidget', 'PaginateWidget', function($compile, SearchWidget, PaginateWidget) { return { setForm: function(form) { this.form = form; }, attr: function(obj, key) { var result; switch(key) { case 'ngClick': result = "ng-click=\"" + obj[key] + "\" "; break; case 'ngOptions': result = "ng-options=\"" + obj[key] + "\" "; break; case 'ngChange': result = "ng-change=\"" + obj[key] + "\" "; break; case 'ngShow': result = "ng-show=\"" + obj[key] + "\" "; break; case 'ngHide': result = "ng-hide=\"" + obj[key] + "\" "; break; case 'trueValue': result = "ng-true-value=\"" + obj[key] + "\" "; break; case 'falseValue': result = "ng-false-value=\"" + obj[key] + "\" "; break; case 'awToolTip': result = "aw-tool-tip=\"" + obj[key] + "\" "; break; case 'awPopOver': result = "aw-pop-over='" + obj[key] + "' "; break; case 'dataTitle': result = "data-title=\"" + obj[key] + "\" "; break; case 'dataPlacement': result = "data-placement=\"" + obj[key] + "\" "; break; default: result = key + "=\"" + obj[key] + "\" "; } return result; }, icon: function(icon) { return " "; }, has: function(key) { return (this.form[key] && this.form[key] != null && this.form[key] != undefined) ? true : false; }, inject: function(form, options) { // // Use to inject the form as html into the view. View MUST have an ng-bind for 'htmlTemplate'. // Returns scope of form. // var element; if (options.modal) { element = angular.element(document.getElementById('form-modal-body')); } else { element = angular.element(document.getElementById('htmlTemplate')); } this.mode = options.mode; this.modal = (options.modal) ? true : false; this.setForm(form); element.html(this.build(options)); // Inject the html this.scope = element.scope(); // Set scope specific to the element we're compiling, avoids circular reference // From here use 'scope' to manipulate the form, as the form is not in '$scope' $compile(element)(this.scope); if ((!options.modal) && options.related) { this.addListeners(); } if (options.mode == 'add') { this.applyDefaults(); } if (options.modal) { this.scope.formHeader = (options.mode == 'add') ? form.addTitle : form.editTitle; $('#form-modal').modal(); } return this.scope; }, applyDefaults: function() { for (fld in this.form.fields) { if (this.form.fields[fld].default || this.form.fields[fld].default == 0) { if (this.form.fields[fld].type == 'select' && this.scope[fld + '_options']) { this.scope[fld] = this.scope[fld + '_options'][this.form.fields[fld].default]; } else { this.scope[fld] = this.form.fields[fld].default; } } } }, reset: function() { // The form field values cannot be reset with jQuery. Each field is tied to a model, so to clear the field // value, you have clear the model. this.scope[this.form.name + '_form'].$setPristine(); for (var fld in this.form.fields) { this.scope[fld] = ''; this.scope[fld + '_api_error'] = ''; this.scope[this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField] = ''; if ( this.form.fields[fld].type == 'lookup' && this.scope[this.form.name + '_form'][this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField] ) { this.scope[this.form.name + '_form'][this.form.fields[fld].sourceModel + '_' + this.form.fields[fld].sourceField].$setPristine(); } if (this.scope[this.form.name + '_form'][fld]) { this.scope[this.form.name + '_form'][fld].$setPristine(); } if (this.form.fields[fld].awPassMatch) { this.scope[this.form.name + '_form'][fld].$setValidity('awpassmatch', true); } if (this.form.fields[fld].ask) { this.scope[fld + '_ask'] = false; } } if (this.mode == 'add') { this.applyDefaults(); } }, addListeners: function() { // Listen for accordion collapse events and toggle the header icon $('.collapse') .on('show', function() { var element = $(this).parent().find('.accordion-heading i'); element.removeClass('icon-angle-down'); element.addClass('icon-angle-up'); }) .on('hide', function() { var element = $(this).parent().find('.accordion-heading i'); element.removeClass('icon-angle-up'); element.addClass('icon-angle-down'); }); }, headerField: function(fld, field, options) { var html = ''; if (field.label) { html += "\n"; } html += "'; if (field.awPopOver) { html += " "; } html += (field.icon) ? this.icon(field.icon) : ""; html += field.label + '' + "\n"; html += "
\n"; html += (field.clear) ? "
\n" : ""; if (field.control === null || field.control === undefined || field.control) { html += "\n"; html += "
\n"; } if (field.ask) { html += " \n"; } html += "
\n"; // Add error messages if ( (options.mode == 'add' && field.addRequired) || (options.mode == 'edit' && field.editRequired) ) { html += "A value is required!\n"; } if (field.type == "email") { html += "A valid email address is required!\n"; } if (field.awPassMatch) { html += "Must match Password value\n"; } html += "\n"; } html += "
\n"; html += "\n"; } } //textarea fields if (field.type == 'textarea') { if ( (! field.readonly) || (field.readonly && options.mode == 'edit') ) { html += "
'; if (field.awPopOver) { html += " "; } html += field.label + '' + "\n"; html += "
\n"; html += "