<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<link rel="stylesheet" href="style.css">
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap-combined.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.js"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/js/bootstrap.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div class='span12'>
<form name='TestForm' ng-submit='addUser()'>
<legend>Add User Form</legend>
<div control-group='TestForm.userName'>
<label for='userName'>Name</label>
<input type="text" name="userName" ng-model='user.name' user-name-validation required />
<form-error key='TestForm.userName.$error.minlength'>User name cannot be less than 9 characters</form-error>
<form-error key='TestForm.userName.$error.maxlength'>User name cannot be more than 9 characters</form-error>
<form-error key='TestForm.userName.$error.conflict'>User {{ user.name }} already exists</form-error>
</div>
<div control-group='TestForm.userAge'>
<label for='userAge'>Age</label>
<input type="text" name="userAge" ng-model='user.age' user-age-validation />
<form-error key='TestForm.userAge.$error.integer'>Age must be an integer</form-error>
<form-error key='TestForm.userAge.$error.too_old'>The user is older than 30</form-error>
<form-error key='TestForm.userAge.$error.too_young'>The user is younger than 5</form-error>
</div>
<div control-group='TestForm.usercolor'>
<label for='usercolor'>Color</label>
<select name='userColor' ng-model='user.color' ng-options='c for c in colors' required>
<option value="">Select a color</option>
</select>
</div>
<div class='form-actions'>
<button class='btn btn-primary' ng-class='{disabled:TestForm.$invalid}'>Add User</button>
<form-error key='TestForm.$invalid && TestForm.$dirty'>This form has errors</form-error>
</div>
</form>
<hr />
<h3>Existing Users</h3>
<table class='table table-bordered'>
<thead>
<th>Name</th>
<th>Age</th>
<th>Favorite Color</th>
</thead>
<tr ng-repeat='u in users'>
<td>{{ u.name }}</td>
<td>{{ u.age }}</td>
<td>{{ u.color }}</td>
</tr>
</table>
<hr />
<div class="alert alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<h4>Warning!</h4>
This may not work in IE8
</div>
</div>
</body>
</html>
/* Put your css in here */
var app = angular.module('plunker', ['plunker.mock']);
app.controller('MainCtrl', function($scope, User, Color) {
$scope.colors = Color.query();
$scope.user = {};
$scope.addUser = function() {
if($scope.TestForm.$valid) {
User.save($scope.user);
$scope.user = {};
$scope.users = User.query();
}
}
$scope.findUsers = function() {
$scope.users = User.query();
}
$scope.findUsers();
});
app.directive('controlGroup', function() {
return {
templateUrl: 'p_control-group.html',
transclude: 'element',
replace: true,
scope: { controlGroup: '=controlGroup' },
link: function(scope) {
console.log(scope)
}
};
});
app.directive('formError', function(){
return {
restrict: 'EMCA',
templateUrl: 'p_form-error.html',
transclude: 'true',
replace: true,
scope: { inputKey : '=key'},
};
});
app.directive('userNameValidation', function(){
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function(scope, element, attrs, ngModel) {
if(!ngModel) return; // do nothing if no ng-model
var isConflict = function(value) {
var conflict = false;
angular.forEach(scope.users, function(u) {
console.log(value, u, scope.users);
if(u.name === value) {
conflict = true;
}
});
return conflict;
}
var validator = function(value) {
ngModel.$setValidity('minlength', !(value.length < 9));
ngModel.$setValidity('maxlength', !(value.length > 9));
ngModel.$setValidity('conflict', !isConflict(value));
return value;
};
ngModel.$parsers.push(validator);
}
};
});
app.directive('userAgeValidation', function(){
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function(scope, element, attrs, ngModel) {
if(!ngModel) return; // do nothing if no ng-model
function AgeValidationSpec(value) {
var age = value;
return {
get isInteger() {
return /^[0-9]+$/.test(value);
},
get isLessThan30() {
return age <= 30;
},
get isOlderThan5() {
return age >= 5;
},
}
}
var validator = function(value) {
var spec = AgeValidationSpec(value);
ngModel.$setValidity('integer', spec.isInteger);
ngModel.$setValidity('too_young', spec.isOlderThan5);
ngModel.$setValidity('too_old', spec.isLessThan30);
return value;
};
ngModel.$parsers.push(validator);
}
};
});
var mock = angular.module('plunker.mock', []);
mock.factory('User', function() {
var users = [];
users.push({
name: 'DEFAULT',
age: '999',
color: 'blue'
})
return {
query: function() {
return users;
},
save: function(user) {
users.push(angular.copy(user));
}
}
});
mock.factory('Color', function() {
return {
query: function() {
return ['red', 'blue', 'green'];
}
}
});
<h1>lol</h1>
<span class='help-inline' ng-transclude ng-show='inputKey'></span>
<div ng-transclude class='control-group' ng-class=' { error: controlGroup.$invalid && controlGroup.$dirty, success: controlGroup.$valid && controlGroup.$dirty }'></div>