Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I'm calling a function from my custom directive on button click.

This is the code I've in my JSP

<input type="button" value="button" text="{{item.id}}" data-href="divSlide" show-notifications>

This is my custom directive

    hello.directive("showNotifications", ["$interval", function($interval, $scope) {
    return {
        restrict: "A",
        link: function(scope, elem, attrs) {            
            //On click
            $(elem).click(function() {
                console.log('before');              
                scope.$parent.getJSON(scope.text);
               if ($('tr#' + $(this).data("href")).is(":visible")) {
                    $('tr#' + $(this).data("href")).remove();
                } else {

                    console.log('after');
                    $(this).closest('tr').after('<tr id="' + $(this).data("href") + '"><td colspan="5">' + $('#' + $(this).data("href")).html() + '</td></tr>');                    
                }    
            });
        },
        scope:{
            text: "@text"
        }
    };
}]);

And this is my function

$scope.getJSON= function(id){
        jsonService.getJSONData(id).then(function(data){
            $scope.data= [];                
                $scope.data= data['dataList'];
                console.log('insidejson');              
            }
           });
    };

When I execute the code the console prints the logs in the below order,

before
after
insidejson

But ideally it should be

before 
insidejson
after

Why is it executing the next statement after the function call before the function gets executed?

What am I doing wrong?

share|improve this question
    
$.getJSON is async. You need to wait for it to finish. return the promise from getJSON and do scope.$parent.getJSON().then(....). – RGraham Apr 13 '15 at 11:30
    
as a side note, there is probably a cleaner way to do what this directive is doing in angular without resorting to jquery.... – Claies Apr 13 '15 at 11:38
up vote 2 down vote accepted

You have to return the promise and use it:

$scope.getJSON= function(id){
  return jsonService.getJSONData(id).then(function(data){

$(elem).click(function() {
  var $element = $(this);
  console.log('before');
  scope.$parent.getJSON(, scope.text).then(function() {
           if ($('tr#' + $element.data("href")).is(":visible")) {

Note that this would no longer point to the element within the function. So I assigned it to a variable and already wrap it into a jQuery element. I also suggest that you pass the function to the directive:

<input type="button" show-notifications call="getJson">

And in your directive:

scope:{
        text: "@text",
        call: "="
    },
link: function(scope, elem, attrs) {            
        //On click
        $(elem).click(function() {
            console.log('before');              
            scope.call(scope.text).then(...
share|improve this answer
    
Now the execution is right order but am not able to get the dynamic row in the view which is in the if else loop.. $('tr#' + $(this).data("href")).remove(); $(this).closest('tr').after('<tr id="' + $(this).data("href") + '"><td colspan="5">' + $('#' + $(this).data("href")).html() + '</td></tr>'); } – kumareloaded Apr 13 '15 at 12:40
    
@kumareloaded You are right, I forgot that this no longer points to the element. The most straightforward solution is to assign it to a variable and use that one instead of this. I have updated the code. – zeroflagL Apr 13 '15 at 13:15
    
Yes thanks I've figured it out but I've another problem here now. The call to getJSONData sets the scope with data "$scope.data" which I'm using to populate my div and then append the div as a new tr with the data onClick. But the data is set only when the button is clicked twice and not the first time? :( – kumareloaded Apr 13 '15 at 13:25
    
@kumareloaded That probably has to do with the digest cycle. Try to call scope.apply() before the if statement. – zeroflagL Apr 13 '15 at 14:06

the function

   jsonService.getJSONData(id).then(function(data){
        $scope.data= [];                
            $scope.data= data['dataList'];
            console.log('insidejson');              
        }
       });

is an async function. hence it will execute in the end

share|improve this answer

jsonService.getJSONData is async call, so the code continue after this line: scope.$parent.getJSON(, scope.text); without waiting to $scope.getJSON answer.

to solve it, you can use $q service.
just add $q service and use $scope.getJSON function like this:

$scope.getJSON= function(id){
         var deferred = $q.defer();
        jsonService.getJSONData(id).then(function(data){
               console.log('insidejson'); 
                deferred.resolve(data);           
            }
           });
        return deferred.promise;
    };

And:

  $(elem).click(function() {
         console.log('before');              
         scope.$parent.getJSON(scope.text).then(function(data){
               if ($('tr#' + $(this).data("href")).is(":visible")) {
                        $('tr#' + $(this).data("href")).remove();
                    } else {
                        console.log('after');
                        $(this).closest('tr').after('<tr id="' + $(this).data("href") + '"><td colspan="5">' + $('#' + $(this).data("href")).html() + '</td></tr>');                    
                    }    
                       });

                });

Now all the code nested in the then and it will execute after the function getJSON will resolve the data with this line deferred.resolve(data);

share|improve this answer
    
When I do this, the lines inside if else loop is not working, am not able to see the new row getting dynamically created on button click? why is that so? – kumareloaded Apr 13 '15 at 12:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.