@darkobits/formation
Version:
360 lines (304 loc) • 10.9 kB
JavaScript
'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;