9

This is a similar question to this one. I'm still seeing some issues with asynchronous data in my directives. Basically I have directives that I want to pass data into, and this data is fetched asynchronously. I started doing this with the scope property on the directive like this:

scope: {
    myAsyncData: '='
}

In the link function I added a $watch so I could update my model based on a value is in the scope. Something like this:

scope.$watch(scope.foo, function() {
    //logic based on myAsyncData
}

When I did this, I started getting javascript errors because the asynchronous data hadn't returned yet. This is what prompted me to post the question linked above. So, I then changed my $watch to something like this:

scope.$watch(scope.foo, function() {
    if (angular.isDefined(scope.myAsyncData))
    {
        //logic based on myAsyncData
    }
}

When I do this, I don't get the javascript errors. However, the $watch doesn't get run again when the data is returned, and so my view doesn't reflect the model correctly. I tried assigning$scope.foo in a $timeout to trigger the watch after the data is returned, but that seems too dependent on timing and is not very robust.

My question is just what is the correct way of interacting with asynchronous data in the directive? I've seen some examples that get the data in the directive like this:

scope.$eval(attrs.myAsyncData);

This doesn't seem to change anything. Is there anything fundamentally different with this than the myAsyncData: '=' above?

I've started to wonder if I should just get the data through services, but it seems like there would be the exact same issues. I've also had the thought of getting the data directly in the directive, but I don't want to directive to be responsible for getting the data. I only want the directive to be responsible for displaying the data and updating the view as the user interacts with it.

I may be missing something obvious on how this should be done, so any input would me much appreciated.

2
  • try scope.$watch('foo', function() {xxx}). This is how I've been doing my watches - with a string that needs to be evaluated. Commented Sep 19, 2012 at 16:40
  • 2
    @dnc253 Since the code in the accepted answer is gone (link broken), could you summarize how you solved your issue ? Commented Jul 31, 2013 at 21:48

3 Answers 3

14

I couldn't understand very well the Misko Hevery's answer so I decided to use events, and they worked well for me.

In my controller, I loaded the data like this:

$http({method: 'GET', url: 'js/datasets/ips-processed.json'}).
        success(function(data, status, headers, config) {

 //post load code here and...
 $scope.$broadcast("Data_Ready");

In my directive, I put

return {
            restrict: 'A',
            scope: {
                donutid: "=",
                dataset: "="
            },
            link: function(scope, elements, attrs) {
                scope.$on("Data_Ready", function  (){
//here the functionality for this directive

Hope it helps to someone.

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

3 Comments

This saved my life. The reason Misko's answer doesn't work well anymore is because it's from an older Angular version. Either way, this worked perfectly for me. Thank you!
This saved my life as well! I modified my solution and performed the broadcast from $rootScope.$broadcast instead (this was because my requirements were slightly different).
Life saved here as well when I had an ng-required and needed to evaluate it.
6

Came across this answer looking for a solution to the same problem.

After much research, suggest that your use Misko Hevery's solution here to delay loading of the Controller until loading of the XHR has 'resolved'.

This seems to have solved all of my 'asynchronous data loading in Directives' issues.

2 Comments

resolutions are the way to go.
+1 for link to Misko's solution. IMO it should be considered an Angular best practice for everything state/route dependent.
5

A little bit late - but I came accross this post with the same problem and resolved it by providing my $watch call's watchExpression parameter as a function.

scope.$watch(function() {
        return scope.foo;
    },
    function() {
        //logic based on myAsyncData
    }
);

1 Comment

Much more practical to implement and this saved my bacon. Thank you.

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.