Skip to content

Instantly share code, notes, and snippets.

Created August 20, 2014 03:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/8c907ec213279c632fdc to your computer and use it in GitHub Desktop.
Save anonymous/8c907ec213279c632fdc to your computer and use it in GitHub Desktop.
<!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>
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