0

I need a directive that performs an API request as a $parsers function.

<input type="text" name="referer" id="referer" ng-model="Subscribe.user.referer" check-referer>

My directive looks like

app.directive('checkReferer', [ 'subscriptionService', function( subscriptionService ) {
return {
        restrict: 'A',
        require: 'ngModel',
        link: function( scope, element, attrs, ngModel ) {
            ngModel.$parsers.unshift( function( viewValue ) {
                subscriptionService.checkReferer( viewValue )
                    .then(function( response ) {
                        if ( typeof response.data == 'object') {
                            ngModel.$setValidity('validReferer', true );
                            return viewValue;
                        }
                    });
             });
}])

I shortened the code a little bit for readability. The service is super straightforward (inside a service):

subscriptionService.checkReferer: function( email ) {
    var promise = $http.get( settings.ApiUrl + 'check-referer/' + email )
        .then( function( response ) {
            return response;
        }, function(response) {
            // error handling here
        })
    return promise;
 },

Problem is: when i 'return viewValue' after the promise has been loaded, the $modelValue doesn't change, so basically the promise doesn't alter the Subscribe.user.referer passed via ng-model to the directive. Everything is fine if i return anything different than a promise, so the problem is there, don't know how to solve it :(

I have no problems if i pass the value i want to change as an attribute to directive's scope. But that's not how i wanna do that :)

I'm not super familiar with Angular but I've been using it for a while now. It took me the whole morning to try to find an answer myself. No luck. And a bit frustrated.

Any help is GREATLY appreciated.

1 Answer 1

1

Reason why you are not getting the data back into your directive is, service is taking time to return the promise to the directive in between that time two way binding is already performed by the angular.. That's one of the common problem with asynchronous calls.

So there are multiple solutions for this you can make your service synchronous in nature

xhr.open(method, url, true);

have a look into this link

Nest solution is wait till the data is reached into the service

// Make a remote request.
$http.get('some wonderful URL for a service').then(function (results) {
  superImportantInfo = results;

  semaphore = true;
});

while (!semaphore) {
  // We're just waiting.
}

Another solution is

var retrieveEventDetails = function(events) {
    // events is array

    var deferred = $q.defer();
    var promise = deferred.promise;

    var retrieveData = function(data) {
        return function(){      
            return $http({
                url: '/api/eventdetails',
                method: 'POST',
                data: {
                    event_number: data.number
                },
                isArray: true
            })
        }
    }

    deferred.resolve();

    return events.reduce(function(promise, single_event){
        return promise.then(retrieveData(single_event));
    }, promise);
}

Hope this help!

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your time, sir! I really like the "Another solution" but I kinda want to keep it async. My point was updating the model asynchronously using Angular's built in $parsers. Lot of people uses signals, which I don't like. I did it by passing the model via directive scope, but still feel "inelegant" :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.