Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you handle asynchronous data in directives for AngularJS

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.

like image 655
dnc253 Avatar asked Sep 19 '12 15:09

dnc253


3 Answers

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
    }
);
like image 136
jaker Avatar answered Nov 17 '22 05:11

jaker


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.

like image 34
danivicario Avatar answered Nov 17 '22 05:11

danivicario


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.

like image 6
Matty J Avatar answered Nov 17 '22 06:11

Matty J