UNPKG

@darkobits/formation

Version:
360 lines (304 loc) 10.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.END_SUBMIT_EVENT = exports.BEGIN_SUBMIT_EVENT = exports.NG_FORM_CONTROLLER = undefined; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); // ----------------------------------------------------------------------------- // ----- Form Group Component -------------------------------------------------- // ----------------------------------------------------------------------------- exports.FormGroupController = FormGroupController; var _ramda = require('ramda'); var _Form = require('../Form/Form'); var _config = require('../../etc/config'); var _utils = require('../../etc/utils'); var _constants = require('../../etc/constants'); var _interfaces = require('../../etc/interfaces'); /** * Key at which the Formation form controller will store a reference to the * Angular form controller * * @private * * @type {string} */ var NG_FORM_CONTROLLER = exports.NG_FORM_CONTROLLER = '$ngFormController'; /** * Event name used to signal to child forms that a submit has begun. * * @type {string} */ var BEGIN_SUBMIT_EVENT = exports.BEGIN_SUBMIT_EVENT = '$fmInitiateSubmit'; /** * Event name used to signal to child forms that a submit has ended. * * @type {string} */ var END_SUBMIT_EVENT = exports.END_SUBMIT_EVENT = '$fmTerminateSubmit'; /** * Curried assertType. * * Remaining arguments: * * @param {string} label * @param {any} value * * @return {boolean} */ var assertIsArrayOrNil = (0, _utils.assertType)('Form Group', [Array, undefined]); function FormGroupController($attrs, $compile, $element, $log, $parse, $scope, $transclude) { var FormGroup = this; /** * Control configuration data for the form group. * * @private * * @type {array} */ var controlConfiguration = []; /** * Tracks registered child forms. * * @private * * @type {array} */ var registry = []; // ----- Private Methods ----------------------------------------------------- /** * Curried applyToCollection using our local registry and generating entries * using each member's index in the registry. * * Remaining arguments: * * @param {string} methodName - Method name to invoke on each member. * @param {object|array} [data] - Optional data to disperse to members. */ var applyToRegistry = (0, _ramda.partial)(_utils.applyToCollection, [registry, function (member, index) { return index; }]); // ----- Interfaces ---------------------------------------------------------- /** * Adds the provided child form to the registry and applies model values and * configuration. * * @private * * @param {object} childForm */ _interfaces.RegisterForm.implementedBy(FormGroup).as(function (childForm) { var childFormName = childForm.name; // Ensure there is not another registered child form with the same name as // the form being registered. if (FormGroup.getForm(childFormName)) { (0, _utils.throwError)('Cannot register child form "' + childFormName + '"; another child form with this name already exists.'); } FormGroup.$debug('Registering child form "' + childFormName + '".'); registry.push(childForm); // Configure the child form. (0, _utils.invoke)(_interfaces.Configure, childForm, controlConfiguration[registry.indexOf(childForm)]); }); /** * Updates the form group's configuration data and configures each registered * child form. */ _interfaces.Configure.implementedBy(FormGroup).as(function (config) { assertIsArrayOrNil('configuration', config); // Update our local configuration object. if (Array.isArray(config)) { controlConfiguration = config; } // Delegate to each existing member's Configure method. applyToRegistry(_interfaces.Configure, controlConfiguration); }); /** * Returns the form group's aggregate model values by delegating to the * GetModelValue method of each control, child form, or child form group. * * @return {array} */ _interfaces.GetModelValue.implementedBy(FormGroup).as(function () { // Map the [index, modelValuesObject] entries we get from applyToRegistry // into a list of modelValues objects. return (0, _ramda.map)(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), modelValues = _ref2[1]; return modelValues; }, applyToRegistry(_interfaces.GetModelValue)); }); /** * Sets the the model value(s) for each registered child form. * * @param {array} newValues - Values to set. */ _interfaces.SetModelValue.implementedBy(FormGroup).as(function (newValues) { assertIsArrayOrNil('model values', newValues); // Delegate to each child form's SetModelValue method. applyToRegistry(_interfaces.SetModelValue, newValues); }); /** * Applies "$custom" errors returned from the consumer's submit handler. * Expects a mapping of field names to error messages or child forms. * * @private * * @param {array} errorMessages */ _interfaces.SetCustomErrorMessage.implementedBy(FormGroup).as(function (errorMessages) { assertIsArrayOrNil('error messages', errorMessages); // Delegate to each child form's SetCustomErrorMessage method. applyToRegistry(_interfaces.SetCustomErrorMessage, errorMessages); }); /** * Clear custom error messages on all child forms. * * @private */ _interfaces.ClearCustomErrorMessage.implementedBy(FormGroup).as(function () { applyToRegistry(_interfaces.ClearCustomErrorMessage); }); /** * Resets each child form to a pristine state. Optionally resets the * model values of each child form to the provided value. * * @param {object} [modelValues] */ _interfaces.Reset.implementedBy(FormGroup).as(function (modelValues) { assertIsArrayOrNil('model values', modelValues); // Delegate to each child form's Reset method. applyToRegistry(_interfaces.Reset, modelValues); }); // ----- Angular Lifecycle Hooks --------------------------------------------- /** * Determines whether to use a form or ngForm element based on whether this * instance has a parent form or not. * * @private */ FormGroup.$postLink = function () { $transclude($scope.$parent.$new(), function (compiledElement) { $element.append(compiledElement); }); }; /** * Set up form name and assign controller instance to its name attribute. * * @private */ FormGroup.$onInit = function () { // Auto-generate name if one was not supplied. FormGroup.name = FormGroup.name || 'FormGroup-' + (0, _config.$getNextId)(); // Set debug mode if the "debug" attribute is present. if (Reflect.has($attrs, 'debug')) { FormGroup.$debugging = true; } if (FormGroup.$parentForm) { // If we are a child form, register with our parent form. FormGroup.$parentForm[_interfaces.RegisterForm](FormGroup); } else { // If we are the top-level form, throw an error. (0, _utils.throwError)('Form groups must have a parent form.'); } }; /** * Handles form tear-down and cleanup. * * @private */ FormGroup.$onDestroy = function () { if (FormGroup.$parentForm) { FormGroup.$parentForm.$unregisterForm(FormGroup); } }; // ----- Semi-Private Methods ------------------------------------------------ /** * Passes provided arguments to $log.log if the "debug" attribute is * present on the form element. * * @private * * @param {...arglist} args */ FormGroup.$debug = function () { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (FormGroup.$debugging) { $log.log.apply($log, ['[' + FormGroup.name + ']'].concat(args)); } }; /** * Returns the form group's $scope. Used to compare scope IDs for child form * registration, and for configurable validators. * * @return {object} */ FormGroup.$getScope = function () { return $scope; }; /** * Removes the provided control from the registry. * * @private * * @param {object} control */ FormGroup.$unregisterForm = function (childForm) { FormGroup.$debug('Unregistering child form "' + childForm.name + '".'); registry = (0, _ramda.without)(childForm, registry); }; // ----- Public Methods ------------------------------------------------------ /** * Similar to getControl, returns the first child form from the form registry * that matches the provided name. * * @param {string} formName * @return {object} - Child form instance, if found. */ FormGroup.getForm = function (formName) { var form = (0, _ramda.find)((0, _ramda.propEq)('name', formName), registry); if ((0, _ramda.is)(_Form.FormController, form)) { return form; } }; /** * Returns true if the form group is disabled. * * @return {boolean} */ FormGroup.isDisabled = function () { return FormGroup.$disabled || FormGroup.$ngDisabled || FormGroup.$parentForm && FormGroup.$parentForm.isDisabled(); }; /** * Disables the form and any controls that implement `isDisabled`. */ FormGroup.disable = function () { FormGroup.$disabled = true; }; /** * Enables the form and any controls that implement `isDisabled`. * * Note: The form may still remain disabled via `ngDisabled`. */ FormGroup.enable = function () { FormGroup.$disabled = false; }; // Expose select interfaces. FormGroup.configure = FormGroup[_interfaces.Configure]; FormGroup.getModelValues = FormGroup[_interfaces.GetModelValue]; FormGroup.reset = FormGroup[_interfaces.Reset]; FormGroup.setModelValues = FormGroup[_interfaces.SetModelValue]; } FormGroupController.$inject = ['$attrs', '$compile', '$element', '$log', '$parse', '$scope', '$transclude']; (0, _config.$registerComponent)(_constants.FORM_GROUP_COMPONENT_NAME, { require: { $parentForm: '?^^' + _constants.FORM_COMPONENT_NAME }, bindings: { name: '@', $ngDisabled: '<ngDisabled' }, transclude: true, controller: FormGroupController, controllerAs: 'FormGroup' }); exports.default = FormGroupController;