0

I have this function which returns json with $scope.product_owners = data

$http({
    url: "php/functions.php",
    method: "GET",
    params: { 
        action: "get_product_owners"
    }
}).success(function(data) {
    $scope.product_owners = data;
});  

Currently, I'm calling this function in all my controllers because it is used in them, but I'm wondering if it was possible to call once. For example, with the $rootScope or something like that.

4 Answers 4

3

The "Angular way" for sharing data across controllers is to use a service:

app.factory('ProductOwners', function ($http) {
    var service = {
        data: []
    };

    $http({
        url: "php/functions.php",
        method: "GET",
        params: { 
            action: "get_product_owners"
        }
    }).success(function(data) {
        service.data = data;
    });

    return service;
});

Then inject the service in every controller:

app.controller('someCtrl', function (ProductOwners) {
    $scope.product_owners = ProductOwners.data;
});

A different implementation with "lazy" evaluation (i.e. it only makes the call if it is needed and then serves the same data):

app.factory('ProductOwners', function ($http, $q) {
    var data;

    function getDataIfNeeded() {
        if (data !== undefined) {
            return $q.when(data);
        }

        return $http({
            url: "php/functions.php",
            method: "GET",
            params: { 
                action: "get_product_owners"
            }
        }).then(function(response) {
            data = response.data;
            return data;
        });
    }

    return {
        getData: getDataIfNeeded
    };
});

app.controller('someCtrl', function (ProductOwners) {
    ProductOwners.getData().then(function (data) {
        $scope.product_owners = data;
    });
});

UPDATE

Yet another different implementation with "lazy" evaluation and supporting an argument passed to getData():

app.factory('GenericService', function ($http, $q) {
    var data = {};

    function getDataIfNeeded(action) {
        action = action || 'default';

        if (data[action] !== undefined) {
            return $q.when(data[action]);
        }

        return $http({
            url: "php/functions.php",
            method: "GET",
            params: { 
                action: action
            }
        }).then(function(response) {
            data[action] = response.data;
            return data[action];
        });
    }

    return {
        getData: getDataIfNeeded
    };
});

app.controller('someCtrl', function (GenericService) {
    GenericService.getData("get_product_owners").then(function (data) {
        $scope.product_owners = data;
    });
});
Sign up to request clarification or add additional context in comments.

10 Comments

I'm little confused. You said service but you use factory. I think it's not the same ? And what do you think about the @z.a's first solution ? Yours seems really great but complicated ?
Regarrding service vs factory: It is one of the most confusing things about Angular (especially for newcomers), but you can register an Angular "service" with many different functions (including provider(), factory(), service(), constant(), value() etc). Actually all of them internally use the provider() function and are only syntactic sugar for simpler cases (such as yours). So, yes, calling app.factory(...) will make you an Angular service.
Regarding @z.a. 's answers vs mine: The first answer of z.a. is identical to my first answer (so no comment there). My second answer is indeed more complicated but provides the benefit that the data is fetched from the server only if needed (e.g. if someone asks for them). If the dataset isn't of negligible size or you are targeting mobile devices (where the number of requests has a noticable impact) this answer is worth the extra complication.
Finally, I wouldn't recommend @z.a. 's second answer, because it might lead to obscure bugs where some child scope's property "shadows" the mainCtrl's product_owners (property). Not to mention how testability and maintainability are negatively impacted. It is generally considered good practice to share data using services (hints: injectable + singleton).
@Steffi: I had a bug in my last update (forgot to initialize data). I corrected my answer (replacing var data; with var data = {};). It should work correclty now.
|
2

If the same code is used by several controllers in your application, you may wish to put it inside a service and then you can call it from the controllers:

myApp.service('products', function($http) {
    this.getProductOwners = function(targetScope) {
        $http({
            url: "php/functions.php",
            method: "GET",
            params: { 
                action: "get_product_owners"
            }
        }).success(function(data) {
            targetScope.product_owners = data;
        });  
    };
});

And then, in your controllers:

myApp.controller('MyCtrl', function($scope, products) {
    products.getProductOwners($scope);
});

Using services is the preferred way for code reuse between several controllers.

Comments

2

1- you can make a factory and then call it when needed inside controllers

yourApp.factory('httpFactory', function($http) {
return {
$http({
    url: "php/functions.php",
    method: "GET",
    params: { 
        action: "get_product_owners"
    }
}).success(function(data) {
    this.product_owners = data;
}); 
}}

then basically you inject it in to wherever,

yourApp.controller('xCtrl', function (httpFactory) {
    $scope.product_owners = httpFactory.product_owners;
});

2- you can also have a main controller for the app like this

<body ng-controller="mainCtrl">

and then put your code in that

yourApp.controller('mainCtrl', function($scope, $http) {
$http({
    url: "php/functions.php",
    method: "GET",
    params: { 
        action: "get_product_owners"
    }
}).success(function(data) {
    $scope.product_owners = data;
}); }

now you can access this data from any schild scope

Comments

0

You can definitely place it on the $rootScope to save multiple calls.

Question is - if you place the one call on one controller, is it possible to go to a different view/controller and thus skipping the call ?

If the answer is no then you have no problem.

If the answer is yes then you should have a controller wrapping all the other ones to make sure you have that data.

Another possibility is have a service to keep the product_owners data, and each controller can access that server to get the data, and if it's not available, get it by the ajax request.

Comments

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.