StackOverflow_24227903: angular-form-validation-but-not-using-inputs
Illustration of answer to http://stackoverflow.com/questions/24227903/angular-form-validation-but-not-using-inputs.
by ExpertSystem
HTML
<script src="http://code.angularjs.org/1.2.18/angular.min.js"></script>
<div ng-controller="myCtrl">
<h3>Send a message</h3>
<hr />
<form name="myForm" ng-submit="sendMessage()" novalidate>
<b>Message text:</b>
<input type="text" name="msgText" ng-model="message.text"
placeholder="Enter your message..." required />
<hr />
<b>Choose one or more message-types:</b>
<div>
Email:
<input type="text" name="rcpEmail" ng-model="recipient.email"
placeholder="Send email to..." required-any="msgType" />
<br />
Modile:
<input type="text" name="rcpMobile" ng-model="recipient.mobile"
placeholder="Send SMS to..." required-any="msgType" />
<br />
Address:
<input type="text" name="rcpAddress" ng-model="recipient.address"
placeholder="Send card to..." required-any="msgType" />
</div>
<hr />
<b>Choose one or more gift-items:</b>
<div>
<input type="checkbox" name="itemFlowers" ng-model="items.flowers"
required-any="giftItems" />
Flowers
|
<input type="checkbox" name="itemCake" ng-model="items.cake"
required-any="giftItems" />
Cake
|
<input type="checkbox" name="itemBook" ng-model="items.book"
required-any="giftItems" />
Book
</div>
<hr />
<button type="submit" ng-disabled="myForm.$invalid">Send message</button>
</form>
</div>
JavaScript
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.sendMessage = function () {
if ($scope.myForm.$invalid) return;
alert('Message sent !');
};
});
app.directive('requiredAny', function () {
// Hash for holding the state of each group
var groups = {};
// Helper function: Determines if at least one control
// in the group is non-empty
function determineIfRequired(groupName) {
var group = groups[groupName];
if (!group) return false;
var keys = Object.keys(group);
return keys.every(function (key) {
return (key === 'isRequired') || !group[key];
});
}
return {
restrict: 'A',
require: '?ngModel',
scope: {}, // an isolate scope is used for easier/cleaner
// $watching and cleanup (on destruction)
link: function postLink(scope, elem, attrs, modelCtrl) {
// If there is no `ngModel` or no groupName has been specified,
// then there is nothing we can do
if (!modelCtrl || !attrs.requiredAny) return;
// Get a hold on the group's state object
// (if it doesn't exist, initialize it first)
var groupName = attrs.requiredAny;
if (groups[groupName] === undefined) {
groups[groupName] = {isRequired: true};
}
var group = scope.group = groups[groupName];
// Clean up when the element is removed
scope.$on('$destroy', function () {
delete(group[scope.$id]);
if (Object.keys(group).length <= 1) {
delete(groups[groupName]);
}
});
// Updates the validity state for the 'required' error-key
// based on the group's status
function updateValidity() {
if...