1

So Im building an app and I'm trying to implement the structure of the app so that its robust and scalable in future.

My app is mostly divided into JavaScript Modules (revealing pattern):

// filter.js file
//My javascript module structure
var filter = (function(){

var _privateMethod = function(){
}

var publicMethod = function(){
    _privateMethod();
}

return{
   publicMethod: publicMethod
}
});

Now the main issue is that I want to use AngularJS within my app too and AngularJs has its own angular modules like so:

// app.js file
var myApp =  angular.module('myApp',[]);
myApp.controller('myController', function($scope){

});

The way I have planned my app developed is:

  1. All HTTP calls to the server will be done within my JavaScript module or to be more clear within my "filter.js" file (see above)
  2. Returned data from the HTTP calls to server will then be sent back to angularjs controller or in my case the "app.js" file (see above) and that controller/app.js file will be responsible for updating my view/html file.

The reason for doing this is so that all my functions that connect with server and handle data are within a private scope (the filter.js module) and no one should have access to those functions as they are being kept out of the global scope.

But to pass data from my filter.js file to my Angular app.js controller I had to use callbacks.

Below is the complete code of my above described scenario:

filter.js

var filter = (function(){

// public method
var testMethod = function(callback){
  loadDoc(function(dta){
    alert(dta);
    callback(dta);
 })
};

// private Method
function loadDoc(callback) {
  // Create the XHR object to do GET to /data resource  
  var xhr = new XMLHttpRequest();
  var dta;
  xhr.open("GET","url",true);

  // register the event handler
  xhr.addEventListener('load',function(){
  if(xhr.status === 200){
       //alert("We got data: " + xhr.response);
        dta = xhr.response;
        callback(dta);
   }
  },false) 

  // perform the work
  xhr.send();
  }

 return {
     testMethod: testMethod   
  };

})();

app.js:

var myApp = angular.module('myApp',[]);

myApp.controller('myController', function($scope){


$scope.myFunc = function(){

     filter.testMethod(function(dta){
        alert(dta);
        $scope.test = dta;
        console.log($scope.test);
      });
   };
});

You can see from my above code structure that I am using callbacks to send data back to my controllers.

My Question:

  1. My question is that the above descried scenario of how I see my code implementation and structure, is that right approach?

  2. Does the implementation adhere to good, clean and correct javascript code?

  3. Is there something else I can do to improve my app's code structure?

1

I would argue that, in the case of AngularJS, utilizing callbacks is a code smell. I say this for the pure simple fact that AngularJS includes the notion of promises that you can leverage for the same use-case, and in fact look extremely similar in practice to the code you have already developed. Consider your test method:

var testMethod = function() {
  return loadDoc();
};

function loadDoc(callback) {
    // Create the XHR object to do GET to /data resource  
    var xhr = new XMLHttpRequest();
    var dta, 
        // This is the deferred action
        defer = $q.defer(); 
    xhr.open("GET","url",true);

    // register the event handler
    xhr.addEventListener('load',function() {
        if(xhr.status === 200) {
            // We have a response, tell those who are waiting
            // about it
            defer.resolve(xhr.response);
        }

    }, false) ;

    // perform the work
    xhr.send();

    return defer.promise;
}

The calling code could look like this:

testMethod().then(function(data) {
    console.log('data', data);
});

Not only that, but the calling code could also look like this:

function callTheTestMethod() {
    return testMethod().then(function(data) {
        console.log('data', data);

        return data;
    });
}

And the code calling that code could look like this:

callTheTestMethod().then(function(data) {
    console.log('I have data here, too', data);
});

Another benefit to using promises is that they already have a built-in way to handle failures:

if(xhr.status === 200) {
    defer.resolve(xhr.response);
} else if(xhr.status > 400 && xhr.status < 600) {
    defer.reject();
}

Just glancing at your code, it looks like your callback is actually being called twice, and to me looks like a bug. Also, on a side note, I don't think you should be instantiating your own version of XMLHttpRequest here vs just using the Angular $http service, but perhaps you have your reasons.

I would suggest this approach: Build an AngularJS service that uses the built in $http service to abstract away your API Calls, something like this:

angular.module('my.module', [])
    .service('TestService', [
        '$http',
        function($http) {
            return {
                testMethod: testMethod
            };

            function testMethod() {
                // Just a simple example to illustrate private 
                // method usage..
                var data = privateMethod();
                return $http.get('url/' + data);
            }

            // Since this function isn't returned in the object above, only
            // code that exists in this scope can actually reference it
            function privateMethod() {
                return '3';
            }
        }
    ])
;

You can consume this service in a controller (or directive, or another service) in this fashion:

angular.module('app.module', ['my.module'])
    .controller('TestController', [
        'TestService',
        function(TestService) {

            activate(); // Prepare for Angular 2.0!

            function activate() {
                TestService.testMethod().then(
                    function(data) {
                        console.log('I still have data', data);
                    },
                    function() {
                        console.log('something went wrong...');
                    }
                );
            }
        }
   ])
;
  • Thank you so much for the answer.What I understand from this ( and correct me if Im wrong ) that using callbacks in AngularJs is not a good practice and instead Promises should be used instead of call backs when using AngularJs, is this correct? The 2nd thing that I would really like to get a clarification on is the use JavaScript Modules (revealing pattern) with AngularJs Modules. Do you think that concept or logic is justified. Or should I completely remove the JavaScript Modules and handle all calls to the API/Server from my AngularJs using the built in $http service. Again Thank you! – Lorenzo von Matterhorn Jan 26 '16 at 20:11
  • Just to clarify, the reason I am trying to use JavaScript Module Pattern is to provide privacy to functions hence making my app more secure. Also this way I can separate all the major functions of my app into modules and that would make scaling and debugging the app in future much much easier. – Lorenzo von Matterhorn Jan 26 '16 at 20:14
  • AngularJS already includes the notion of modules, and I've shown you above how you can make one depend on the other (just focus on the first line of the last snippet). If the only thing your public method does is call your private method, then your private method is not private because it's been aliased by the public one. – Jeff Lambert Jan 26 '16 at 20:19
  • @LorenzovonMatterhorn FYI- I took another look and updated the example I used to give you a sense of how you can utilize a private method within your service. Nothing outside of the TestService will be able to reference privateMethod in order to call it. Because of how it's defined and JavaScript's scope hoisting, any other function defined in the service will be able to reference it. – Jeff Lambert Jan 27 '16 at 0:35
  • @LorenzovonMatterhorn Generally speaking, using callbacks is fine in Angular. Promises don't make sense everywhere. But this case is definitely a situation where promises apply, and you don't really have a choice if you use the $http service. And you should definitely use the $http service to make Ajax calls. – Mohair Jan 27 '16 at 3:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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