-
-
Save funkytaco/a53bf7009d3e81e2d4a8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html ng-app="myApp" ng-controller="myCtrl"> | |
<head> | |
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js"></script> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script> | |
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> | |
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css"> | |
</head> | |
<body> | |
<form name="the_form"> | |
<div class="form-group has-feedback" ng-class="{'has-success':userNameUnique.valid, 'has-warning':userNameUnique.invalid}"> | |
<label for="user_name">Username</label> | |
<input | |
class="form-control" | |
name="user_name" | |
ng-model="foo" | |
pmkr-validate-custom="{name:'unique', fn:check, gate:gate, wait:500, props:'userNameUnique'}" | |
pmkr-pristine-original | |
> | |
<span class="glyphicon glyphicon-ok form-control-feedback" ng-show="userNameUnique.valid"></span> | |
<span class="glyphicon glyphicon-warning-sign form-control-feedback" ng-show="userNameUnique.invalid"></span> | |
<i class="glyphicon glyphicon-refresh fa-spin form-control-feedback form-control-feedback" ng-show="userNameUnique.pending"></i> | |
<p class="alert alert-success" ng-show="userNameUnique.valid">"{{userNameUnique.checkedValue}}" is availiable.</p> | |
<p class="alert alert-warning" ng-show="userNameUnique.invalid">"{{userNameUnique.checkedValue}}" is not availiable.</p> | |
</div> | |
<button | |
class="btn btn-default" | |
ng-click="submit()" | |
ng-disabled="profile_form.$invalid || userNameUnique.pending" | |
>Submit</button> | |
</form> | |
<script id="jsbin-javascript"> | |
angular.module('myApp', [ | |
'ui.router' | |
]) | |
.config([ | |
'$stateProvider', | |
function($stateProvider) { | |
} | |
]) | |
.controller('myCtrl', function($scope, $q, $timeout) { | |
$scope.foo = '123'; | |
var flag = false; | |
// alternate success / fail from the server | |
$scope.check = function() { | |
var deferred = $q.defer(); | |
flag = !flag; | |
$timeout(function() { | |
deferred.resolve(flag); | |
}, 250); | |
return deferred.promise; | |
}; | |
$scope.gate = function(val, $ngModel) { | |
return !val || $ngModel.$pristine; | |
}; | |
}) | |
.directive('pmkrValidateCustom', [ | |
'$q', | |
'pmkr.debounce', | |
function($q, debounce) { | |
var directive = { | |
restrict: 'A', | |
require: 'ngModel', | |
priority: 1, | |
link: function($scope, $element, $attrs, $ngModel) { | |
var opts = $scope.$eval($attrs.pmkrValidateCustom); | |
var props = {}; | |
opts.props && ($scope[opts.props] = props); | |
var valid; | |
var gate = false; | |
$ngModel.$validators[opts.name] = function() { | |
return valid; | |
}; | |
var debouncedFn = debounce(validate, opts.wait); | |
var latestFn = debounce.latest(debouncedFn); | |
function validate(val) { | |
if (gate) { return; } | |
props.validating = true; | |
return opts.fn(val); | |
} | |
function valueChange(val) { | |
props.valid = props.invalid = false; | |
if (opts.gate && (gate = opts.gate(val, $ngModel))) { | |
props.pending = props.validating = false; | |
return; | |
} | |
props.pending = true; | |
latestFn(val).then(function(isValid) { | |
if (gate) { return; } | |
props.checkedValue = val; | |
valid = props.valid = isValid; | |
props.invalid = !valid; | |
$ngModel.$validate(); | |
props.pending = props.validating = false; | |
}); | |
} | |
$scope.$watch(function() { | |
return $ngModel.$viewValue; | |
}, valueChange); | |
} // link | |
}; // directive | |
return directive; | |
} | |
]) | |
.factory('pmkr.debounce', [ | |
'$timeout', | |
'$q', | |
function($timeout, $q) { | |
var service = function() { | |
return debounceFactory.apply(this, arguments); | |
}; | |
service.immediate = function() { | |
return debounceImmediateFactory.apply(this, arguments); | |
}; | |
service.latest = function() { | |
return debounceLatestFactory.apply(this, arguments); | |
}; | |
function debounceFactory(fn, wait) { | |
var timeoutPromise; | |
function debounced() { | |
var deferred = $q.defer(); | |
var context = this; | |
var args = arguments; | |
$timeout.cancel(timeoutPromise); | |
timeoutPromise = $timeout(function() { | |
deferred.resolve(fn.apply(context, args)); | |
}, wait); | |
return deferred.promise; | |
} | |
return debounced; | |
} | |
function debounceImmediateFactory(fn, wait) { | |
var timeoutPromise; | |
function debounced() { | |
var deferred = $q.defer(); | |
var context = this; | |
var args = arguments; | |
if (!timeoutPromise) { | |
deferred.resolve(fn.apply(context, args)); | |
} | |
$timeout.cancel(timeoutPromise); | |
timeoutPromise = $timeout(function() { | |
timeoutPromise = null; | |
}, wait); | |
return deferred.promise; | |
} | |
return debounced; | |
} | |
function debounceLatestFactory(fn) { | |
var latestArgs; | |
function debounced() { | |
var args = latestArgs = JSON.stringify(arguments); | |
var deferred = $q.defer(); | |
fn.apply(this, arguments).then(function(res) { | |
if (latestArgs === args) { | |
deferred.resolve(res); | |
} | |
}); | |
return deferred.promise; | |
} | |
return debounced; | |
} | |
return service; | |
} | |
]) | |
.directive('pmkrPristineOriginal', [ | |
function() { | |
var directive = { | |
restrict : 'A', | |
require : 'ngModel', | |
link: function($scope, $element, $atts, $ngModel) { | |
var pristineVal = null; | |
$scope.$watch(function() { | |
return $ngModel.$viewValue; | |
}, function(val) { | |
// set pristineVal to newVal the first time this function runs | |
if (pristineVal === null) { | |
pristineVal = $ngModel.$isEmpty(val) ? '' : val.toString(); | |
} | |
// newVal is the original value - set input to pristine state | |
if (pristineVal === val) { | |
$ngModel.$setPristine(); | |
} | |
}); | |
} | |
}; | |
return directive; | |
} | |
]) | |
; | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('myApp', [ | |
'ui.router' | |
]) | |
.config([ | |
'$stateProvider', | |
function($stateProvider) { | |
} | |
]) | |
.controller('myCtrl', function($scope, $q, $timeout) { | |
$scope.foo = '123'; | |
var flag = false; | |
// alternate success / fail from the server | |
$scope.check = function() { | |
var deferred = $q.defer(); | |
flag = !flag; | |
$timeout(function() { | |
deferred.resolve(flag); | |
}, 250); | |
return deferred.promise; | |
}; | |
$scope.gate = function(val, $ngModel) { | |
return !val || $ngModel.$pristine; | |
}; | |
}) | |
.directive('pmkrValidateCustom', [ | |
'$q', | |
'pmkr.debounce', | |
function($q, debounce) { | |
var directive = { | |
restrict: 'A', | |
require: 'ngModel', | |
priority: 1, | |
link: function($scope, $element, $attrs, $ngModel) { | |
var opts = $scope.$eval($attrs.pmkrValidateCustom); | |
var props = {}; | |
opts.props && ($scope[opts.props] = props); | |
var valid; | |
var gate = false; | |
$ngModel.$validators[opts.name] = function() { | |
return valid; | |
}; | |
var debouncedFn = debounce(validate, opts.wait); | |
var latestFn = debounce.latest(debouncedFn); | |
function validate(val) { | |
if (gate) { return; } | |
props.validating = true; | |
return opts.fn(val); | |
} | |
function valueChange(val) { | |
props.valid = props.invalid = false; | |
if (opts.gate && (gate = opts.gate(val, $ngModel))) { | |
props.pending = props.validating = false; | |
return; | |
} | |
props.pending = true; | |
latestFn(val).then(function(isValid) { | |
if (gate) { return; } | |
props.checkedValue = val; | |
valid = props.valid = isValid; | |
props.invalid = !valid; | |
$ngModel.$validate(); | |
props.pending = props.validating = false; | |
}); | |
} | |
$scope.$watch(function() { | |
return $ngModel.$viewValue; | |
}, valueChange); | |
} // link | |
}; // directive | |
return directive; | |
} | |
]) | |
.factory('pmkr.debounce', [ | |
'$timeout', | |
'$q', | |
function($timeout, $q) { | |
var service = function() { | |
return debounceFactory.apply(this, arguments); | |
}; | |
service.immediate = function() { | |
return debounceImmediateFactory.apply(this, arguments); | |
}; | |
service.latest = function() { | |
return debounceLatestFactory.apply(this, arguments); | |
}; | |
function debounceFactory(fn, wait) { | |
var timeoutPromise; | |
function debounced() { | |
var deferred = $q.defer(); | |
var context = this; | |
var args = arguments; | |
$timeout.cancel(timeoutPromise); | |
timeoutPromise = $timeout(function() { | |
deferred.resolve(fn.apply(context, args)); | |
}, wait); | |
return deferred.promise; | |
} | |
return debounced; | |
} | |
function debounceImmediateFactory(fn, wait) { | |
var timeoutPromise; | |
function debounced() { | |
var deferred = $q.defer(); | |
var context = this; | |
var args = arguments; | |
if (!timeoutPromise) { | |
deferred.resolve(fn.apply(context, args)); | |
} | |
$timeout.cancel(timeoutPromise); | |
timeoutPromise = $timeout(function() { | |
timeoutPromise = null; | |
}, wait); | |
return deferred.promise; | |
} | |
return debounced; | |
} | |
function debounceLatestFactory(fn) { | |
var latestArgs; | |
function debounced() { | |
var args = latestArgs = JSON.stringify(arguments); | |
var deferred = $q.defer(); | |
fn.apply(this, arguments).then(function(res) { | |
if (latestArgs === args) { | |
deferred.resolve(res); | |
} | |
}); | |
return deferred.promise; | |
} | |
return debounced; | |
} | |
return service; | |
} | |
]) | |
.directive('pmkrPristineOriginal', [ | |
function() { | |
var directive = { | |
restrict : 'A', | |
require : 'ngModel', | |
link: function($scope, $element, $atts, $ngModel) { | |
var pristineVal = null; | |
$scope.$watch(function() { | |
return $ngModel.$viewValue; | |
}, function(val) { | |
// set pristineVal to newVal the first time this function runs | |
if (pristineVal === null) { | |
pristineVal = $ngModel.$isEmpty(val) ? '' : val.toString(); | |
} | |
// newVal is the original value - set input to pristine state | |
if (pristineVal === val) { | |
$ngModel.$setPristine(); | |
} | |
}); | |
} | |
}; | |
return directive; | |
} | |
]) | |
; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment