AngularJS feature available for multiple controllers

Building a simple dashboard in AngularJS API + Rest .

Built a simple factory that makes an API request (GET, POST)

and returns the required data for a successful callback. The return data must be processed and modified $scope

, as the API can return server side field errors.

I am unable to build handling / change $scope

in the factory since the factory does not (and should not) have access to the scope. I would rather not handle / apply in the success callback as it will be repetitive (once per API request).

What is the best "Angular" way to solve this problem?

One possible solution is for the function to exist outside of the Angular application and then simply pass the scope and data to it.

This looks like a bad job (see below).

myApp.controller("saveForm", ["$scope", "api", function($scope, api), function() {
    ...
    $scope.submit = function() {
        api("POST", url, $scope.data, function(data) {
            //onSuccess
            processData($scope, data);
        });
    }
    ...
}]);

myApp.factory('api', ['$http', function($http) {
    return function(method, url, input, success, error) {
        //Retrieve data from API. Note that factory DOES NOT have access to $scope.
        $http(...
    }
}]);

var processData = function(scope, data) {
    angular.forEach(data, function(value, key)) {
        scope....
    }
}

      

+3


source to share


4 answers


Not sure if I got you, but you can extend controllers in a mixin way:

Base controller

(function() {
  'use strict';

  angular.module('Base', []);

  function BaseController($scope, <injectables>, that) {
    that.mixin1 = function() {
    };

    that.mixin2 = function(arg1, arg2) {
    };
  }

  angular.module('Base').controller('BaseController',
    ['$scope', '...', BaseController]);
})();

      



Legacy controller

(function() {
  'use strict';

  angular.module('Derived', ['Base']);

  function DerivedController($scope, $controller, ...) {
    $controller('BaseController', {
      '$scope' : $scope,
      ...
      'that' : this
    });

    // this.mixin1
    // this.mixin2
  }

  angular.module('Derived').controller('DerivedController',
    ['$scope', '$controller', '...', DerivedController]);
})();

      

Please note that you are using Angular service to bundle $controller

functions.

+1


source


Why not just include a function in the controller that handles it? This is how I usually deal with it:



myApp.controller("saveForm", ["$scope", "api", function($scope, api), function() {
    ...
    $scope.submit = function() {
        api("POST", url, $scope.data, function(data) {
            //onSuccess
            processData(data);
        });
    }
    function provessData(data){
        // do stuff to data
        $scope.foo = data;
    }
    ...
}]);

      

0


source


It seems like your controller is doing too much work and knows too much about the actual request (url, "POST" method, etc.).

How do I convert data in a factory to what the controller expects. factory doesn't need to know anything about scope. It simply converts the data into a format that the controller can use and then sends back. This way the factory can be reused across controllers.

myApp.controller("saveForm", ["$scope", "api", function($scope, api), function() {
    ...
    $scope.submit = function() {

// Call API.update and handle the deferred that is returned, which will be the transformed data
        api.update($scope.data).then(function (transformedData) {
           scope....

        });
    }
    ...
}]);

myApp.factory('api', ['$http', '$q', function($http, $q) {
    return {
         update : function () {

             var deferred = $q.defer();

             $http({
               method: "GET",
               url: "your/url/path"

             }).success(function(data) {

                var transformedData;

                // Perform data transformation here instead of in controllers
                angular.forEach(data, function (value, key) {
                    transformedData.....
                });

                deferred.resolve(transformedData);
             });

             return deferred.promise;
         }
    }
}]);

      

0


source


You can create a factory that returns your function processData

:

myApp.factory('processData', [function () {
    return function(scope, data) {
        angular.forEach(data, function(value, key)) {
            scope....
        }
    };
}]);

      

And then inject it angular:

myApp.controller("saveForm", ["$scope", "api", "processData", function($scope, api, processData) {
    ...
    $scope.submit = function() {
        api("POST", url, $scope.data, function(data) {
            //onSuccess
            processData($scope, data);
        });
    }
    ...
}]);

      

The advantage of this approach in regards to a function declared outside of DI is that it is still easy to mock a dependency processData

in your unit tests if you need to.

0


source







All Articles