OK,
This particular answer helped a lot - Call Function with Delay When Textbox Changes in AngularJS
Here is resulting directive:
app.directive('nickUnique', ['$http', '$timeout', function ($http, $timeout) {
return {
require: 'ngModel',
link: function (scope, ele, attrs, c) {
var timer = false; // for grouping calls
scope.$watch(attrs.ngModel, function () {
// for when $setPristine(true) is called
if (c.$pristine) {
c.$setValidity('httpinprogress', true);
c.$setValidity('nickUnique', true);
}
// only execute for otherwise "valid" nick
if (c.$viewValue != null && c.$dirty &&
c.$viewValue.length >= 4 && c.$viewValue.length <= 12) {
if (timer) {
$timeout.cancel(timer);
}
c.$setValidity('httpinprogress', false);
c.$setValidity('nickUnique', true);
timer = $timeout(function () {
$http.get("/path/to/service", { params: { Nick: c.$viewValue } })
.success(function (data, status, headers, cfg) {
if (data.RequestNick === c.$viewValue) {
c.$setValidity('httpinprogress', true);
c.$setValidity('nickUnique', data.Valid);
}
}).error(function (data, status, headers, cfg) {
c.$setValidity('nickUnique', false);
});
}, 250);
}
});
}
};
}]);
To use it, you just decorate your input like:
<input name="nick" ng-model="myCtrl.Nick" nick-unique />
Your service on /path/to/service should return JSON object like:
{ Valid: true/false, RequestNick: echo_nick_sent }
Finally, you just show validation errors depending on state of $error property. Like, if you also validate required, minlength and maxlength, you'll have something like this:
<span class="error" ng-show="myForm.Nick.$dirty && myForm.Nick.$invalid">
<small class="error" ng-show="myForm.Nick.$error.required">is required field</small>
<small class="error" ng-show="myForm.Nick.$error.minlength">is required to be at least 4 characters</small>
<small class="error" ng-show="myForm.Nick.$error.maxlength">is required to be less than 12 characters</small>
<small class="error" ng-show="!myForm.Nick.$error.required &&
!myForm.Nick.$error.minlength &&
!myForm.Nick.$error.maxlength &&
myForm.Nick.$error.nickUnique">is taken, please try another</small>
</span>