Created
August 20, 2014 03:37
-
-
Save anonymous/8c907ec213279c632fdc to your computer and use it in GitHub Desktop.
// source http://jsbin.com/cuyewi/1
This file contains hidden or 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 hidden or 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