1

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?

2
  • $.getJSON is async. You need to wait for it to finish. return the promise from getJSON and do scope.$parent.getJSON().then(....). Commented Apr 13, 2015 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.... Commented Apr 13, 2015 at 11:38

3 Answers 3

2

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(...
Sign up to request clarification or add additional context in comments.

4 Comments

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 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.
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 That probably has to do with the digest cycle. Try to call scope.apply() before the if statement.
1

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

Comments

1

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);

1 Comment

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?

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.