2

I changed sections (div) of my html to directives, before changing that, my html looks like this:

<div ng-controller="SearchCtrl as search">
    <div id="firstDirective">
        .
        .
        .
    <div>
    <div id="secondDirective">
        .
        .
        .
    <div>
</div>

which works fine with the associated controller. I plan on changing the html to this:

<div ng-controller="SearchCtrl as search">
    <first-directive>
    <second-directive>
</div>

The corresponding angular.directive definitions have isolated scopes (return {..., scope: {attr: '=attr', func: '&func'},...}) and attributes and functions are passed from the controller. After changing the first div to a directive (first-directive), it is still working well. However, after creating the second-directive and replacing the corresponding div, that section does not work anymore (the first still works). Here is my controller:

app.controller('SearchCtrl', ['$scope', '$http', function($scope, $http){

    var self = this;

    self.data = {};

    self.clickSearch = function() {

        self.retrieve(param1, param2);
        .
        .
        .
        console.log('clickSearch log, data: ', self.data);
    }

    // retrieve is reused, called directly in some parts of html, 
    // thus I attached it as a controller function
    self.retrieve = function(param1, param2) {

        // some $http.get and assign to data
        .
        .
        .

        console.log('retrieve log, data:', self.data);
    }
    // some other functions, some are passed to the directives
    .
    .
    .
});

However the logs show:

[LOG]clickSearch log, data: {}
[LOG]retrieve log, data: {...//some assigned values}

It looks like that clickSearch function finishes first, then retrieve function executes later, thus I get empty data. My background is from Java, so I do not fully understand the concept of callback in JavaScript, and I suspect that's what's happening here. How could I remedy this? Thanks.

oikonomiyaki
  • 7,691
  • 15
  • 62
  • 101
  • http://stackoverflow.com/questions/11233633/understanding-asynchronous-code-in-laymans-terms – Vicky Gonsalves Oct 22 '14 at 06:29
  • 1
    From what your code looks like, any call to `clickSearch` will trigger a 'retrieve' log followed by a 'clickSearch' log, because they happen synchronously. However, if one of these statements is nested in another function (a callback) that you pass to a directive, the situation is different. – Valentin Waeselynck Oct 22 '14 at 06:51
  • By the way, this is probably because of your Java background, but there is hardly any reason here to declare `data`, `clickSearch` and `retrieve` as members of `this`. Just declare local variables, it will be simpler to use and reason about. (the reason you don't do this in Java is the lack of support of lexical closures). – Valentin Waeselynck Oct 22 '14 at 06:56
  • @ValentinWaeselynck What do you mean 'local variables'? 'local' of which? inside the controller? It may not be possible to make them local because I need to expose these data and methods as controller properties so that I could invoke them in the html part. – oikonomiyaki Oct 22 '14 at 07:13
  • I mean something like `var data = {};`. And exposing them to HTML consists of making them properties of the `$scope` object, not your controller object. – Valentin Waeselynck Oct 22 '14 at 07:17
  • Ok, it's solved now. It just so happen that my `second-directive` was also defined elsewhere, it was defined twice. I removed the old definition and it worked, the 'asynchronous anomaly' was removed. Thanks. – oikonomiyaki Oct 22 '14 at 07:24

1 Answers1

1

Try this

app.controller('SearchCtrl', ['$scope', '$http', function($scope, $http){

var self = this;

self.data = {};

self.clickSearch = function() {

    self.retrieve(param1, param2, function(data){
       .
       .
       .
        console.log('clickSearch log, data: ', data);
        console.log('clickSearch log, data: ', self.data);
    });
}

// retrieve is reused, called directly in some parts of html, 
// thus I attached it as a controller function
self.retrieve = function(param1, param2, callback) {

    // some $http.get and assign to data
    .
    .
    .

    console.log('retrieve log, data:', self.data);
    callback(data);//$http.get{url:url,success:callback}
}
// some other functions, some are passed to the directives
.
.
.

});

Saidh
  • 1,131
  • 1
  • 12
  • 21