[Forms] Separate out FormController

Separate out the controller for mct-form from its
directive definition, to allow reuse by the
mct-toolbar directive, WTD-684.
This commit is contained in:
Victor Woeltjen 2015-01-15 13:36:21 -08:00
parent b98758daf8
commit 244583b2f7
4 changed files with 132 additions and 48 deletions

View File

@ -4,13 +4,10 @@
* Module defining MCTForm. Created by vwoeltje on 11/10/14.
*/
define(
[],
function () {
["./controllers/FormController"],
function (FormController) {
"use strict";
// Default ng-pattern; any non whitespace
var NON_WHITESPACE = /\S/;
/**
* The mct-form directive allows generation of displayable
* forms based on a declarative description of the form's
@ -37,45 +34,6 @@ define(
"templates/form.html"
].join("/");
function controller($scope) {
var regexps = [];
// ng-pattern seems to want a RegExp, and not a
// string (despite what documentation says) but
// we want form structure to be JSON-expressible,
// so we make RegExp's from strings as-needed
function getRegExp(pattern) {
// If undefined, don't apply a pattern
if (!pattern) {
return NON_WHITESPACE;
}
// Just echo if it's already a regexp
if (pattern instanceof RegExp) {
return pattern;
}
// Otherwise, assume a string
// Cache for easy lookup later (so we don't
// creat a new RegExp every digest cycle)
if (!regexps[pattern]) {
regexps[pattern] = new RegExp(pattern);
}
return regexps[pattern];
}
// Publish the form state under the requested
// name in the parent scope
$scope.$watch("mctForm", function (mctForm) {
if ($scope.name) {
$scope.$parent[$scope.name] = mctForm;
}
});
$scope.getRegExp = getRegExp;
}
return {
// Only show at the element level
restrict: "E",
@ -83,9 +41,8 @@ define(
// Load the forms template
templateUrl: templatePath,
// Use the controller defined above to
// populate/respond to changes in scope
controller: controller,
// Use FormController to populate/respond to changes in scope
controller: FormController,
// Initial an isolate scope
scope: {

View File

@ -0,0 +1,57 @@
/*global define*/
define(
[],
function () {
"use strict";
// Default ng-pattern; any non whitespace
var NON_WHITESPACE = /\S/;
/**
* Controller for mct-form and mct-toolbar directives.
* @constructor
*/
function FormController($scope) {
var regexps = [];
// ng-pattern seems to want a RegExp, and not a
// string (despite what documentation says) but
// we want form structure to be JSON-expressible,
// so we make RegExp's from strings as-needed
function getRegExp(pattern) {
// If undefined, don't apply a pattern
if (!pattern) {
return NON_WHITESPACE;
}
// Just echo if it's already a regexp
if (pattern instanceof RegExp) {
return pattern;
}
// Otherwise, assume a string
// Cache for easy lookup later (so we don't
// creat a new RegExp every digest cycle)
if (!regexps[pattern]) {
regexps[pattern] = new RegExp(pattern);
}
return regexps[pattern];
}
// Publish the form state under the requested
// name in the parent scope
$scope.$watch("mctForm", function (mctForm) {
if ($scope.name) {
$scope.$parent[$scope.name] = mctForm;
}
});
// Expose the regexp lookup
$scope.getRegExp = getRegExp;
}
return FormController;
}
);

View File

@ -0,0 +1,69 @@
/*global define,describe,it,expect,beforeEach,waitsFor,jasmine*/
define(
["../../src/controllers/FormController"],
function (FormController) {
"use strict";
describe("The form controller", function () {
var mockScope,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", [ "$watch" ]);
mockScope.$parent = {};
controller = new FormController(mockScope);
});
it("watches for changes in form by name", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
"mctForm",
jasmine.any(Function)
);
});
it("conveys form status to parent scope", function () {
var someState = { someKey: "some value" };
mockScope.name = "someName";
mockScope.$watch.mostRecentCall.args[1](someState);
expect(mockScope.$parent.someName).toBe(someState);
});
it("allows strings to be converted to RegExps", function () {
// Should have added getRegExp to the scope,
// to convert strings to regular expressions
expect(mockScope.getRegExp("^\\d+$")).toEqual(/^\d+$/);
});
it("returns the same regexp instance for the same string", function () {
// Don't want new instances each digest cycle, for performance
var strRegExp = "^[a-z]\\d+$",
regExp;
// Add getRegExp to scope
regExp = mockScope.getRegExp(strRegExp);
// Same object instance each time...
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
});
it("passes RegExp objects through untouched", function () {
// Permit using forms to simply provide their own RegExp object
var regExp = /^\d+[a-d]$/;
// Should have added getRegExp to the scope,
// to convert strings to regular expressions
expect(mockScope.getRegExp(regExp)).toBe(regExp);
});
it("passes a non-whitespace regexp when no pattern is defined", function () {
// If no pattern is supplied, ng-pattern should match anything
expect(mockScope.getRegExp()).toEqual(/\S/);
expect(mockScope.getRegExp(undefined)).toEqual(/\S/);
});
});
}
);

View File

@ -2,5 +2,6 @@
"MCTControl",
"MCTForm",
"controllers/CompositeController",
"controllers/DateTimeController"
"controllers/DateTimeController",
"controllers/FormController"
]