Reputation: 4224
This is a simple form that contains one input field with a directive. If the input is valid, the directive will call a remote server. The response will populate the form model with some extra data.
How do I wait for the promise to resolve when the form is submitted?
Here's some sample code in case it helps:
app.directive('getSecretStuff', function($q, $http) {
function get_some_secret_stuff( value ) {
var deferred = $q.defer();
$http.get(url)
.success(function (response) {
deferred.resolve(response.secret_stuff);
});
return deferred.promise;
};
return {
restrict: 'A',
require: '^form',
scope: {
secret_stuff: '=stuff',
},
link: function(scope, element, attrs, ctrl) {
scope.$watch(
function() { return ctrl[ element.attr('name') ].$valid; },
function (validity) {
if (validity) {
get_some_secret_stuff( element.val() ).then(function( stuff ) {
scope.secret_stuff = stuff;
});
}
}
);
},
};
});
Upvotes: 1
Views: 1013
Reputation: 41065
You can (mis)use an async validator to do this. Set the form model with extra in the async validator promise and then use the form's $pending
to disable the form's submit button till the promise resolves (if it needs to)
HTML
<div ng-app="myApp">
<div ng-controller="ctrlr">
<form name="form" novalidate ng-submit="!form.$pending && submit()">
<!-- our validaty check is just a sample - check for numbers -->
<input ng-model="publicStuff" name="publicStuff" get-secret-stuff stuff="secretStuff" ng-pattern="/^[0-9]+$/" />
<input ng-model="secretStuff" />
<button type="submit">Go</button>
</form>
</div>
</div>
Script
angular.module('myApp', [])
.controller('ctrlr', function ($scope) {
})
.directive('getSecretStuff', function ($q, $timeout) {
function get_some_secret_stuff(value) {
var deferred = $q.defer();
// for illustration, we use the $timeout instead of $http
// swap this out with the actual $http call in your code
$timeout(function () {
deferred.resolve('secret value for ' + value);
}, 2000)
return deferred.promise;
};
// a promise that resolves immediately
function get_dummy_promise() {
var deferred = $q.defer();
console.log('asd')
deferred.resolve('1');
return deferred.promise;
};
return {
restrict: 'A',
require: ['^form', 'ngModel'],
scope: {
secret_stuff: '=stuff',
},
link: function (scope, element, attrs, ctrlrs) {
// we misuse the async validator to...
ctrlrs[1].$asyncValidators.secretStuff = function (modelValue, viewValue) {
if (viewValue)
return get_some_secret_stuff(viewValue).then(function (response) {
// ...do work other than validation
scope.secret_stuff = response;
return true;
});
else
// this is just for the first run when the validator gets called even if $valid is not set
return get_dummy_promise().then(function (response) {
scope.secret_stuff = undefined;
return true;
});
};
// we probably want to clear out the secret stuff for invalid values
scope.$watch(
function () { return ctrlrs[0][element.attr('name')].$valid; },
function (validity) {
if (!validity) {
scope.secret_stuff = undefined;
}
}
);
},
};
});
Upvotes: 2