Huh? What browser are you using???
Function hoisting will always push function (and variable) declarations to the top of the scope. So the functions are visible before they are declared.
http://designpepper.com/blog/drips/variable-and-function-hoistingI use this reveling module pattern in just about all my javascript code and it definitely works including for Angular modules.
+++ Rick ---
>When I tried this code exactly, I got functions undefined. So I moved implementation on the top and the var service at the bottom and it worked. I also had to declare var metaData at the very top in the code before function declarations.
>
>In any case, after I made that change (e.g. used one service variable instead of return of anonymous object with all function definitions) I still got the same behavior as before.
>
>>That approach works - I use it all the time to cache data. if it doesn't you likely have a logic error somewhere in determining whether the data is already present or you're not storing the data properly in a persistent place where it survives.
>>
>>Your service looks wrong in a number of ways - I don't know how you're accessing it but you wouldn't be able to even call your getMetaData function on the service since its private.
>>
>>This is how I would set this up:
>>
>>
>>app.factory('invoicesService', ['$http', '$q', function($http, $q) {
>>
>> // Interface
>> var service = {
>> metaData: null,
>> getMetaData: getMetaData
>> }
>> return service;
>>
>> // Implementation
>>
>> function getMetaData() {
>> var deferred = $q.defer();
>>
>> if (service.metaData)
>> deferred.resolve(service.metaData);
>> else {
>> $http.get('/api/invoices/metadata')
>> .success(function (data) {
>> service.metaData = data;
>> deferred.resolve(data);
>>
>> })
>> .error(function (data, status, header, config) {
>> deferred.reject(status);
>> });
>> }
>> return deferred.promise;
>> };
>>
>>}
>>
>>
>>You don't have to make the metaData public, but my guess is that's what you actually want so it stays accessible and updateable by external code.
>>
>>+++ Rick ---
>>
>>>Nice article. We use the first approach in our code.
>>>
>>>I tried what you suggested (e.g. my new code is
>>>
>>>
>>>app.factory('invoicesService', ['$http', '$q', function($http, $q) {
>>>
>>> var metaData = null;
>>>
>>> var getMetaData = function () {
>>> var deferred = $q.defer();
>>>
>>> if (angular.isObject(metaData))
>>> deferred.resolve(metaData);
>>> else {
>>> $http.get('/api/invoices/metadata')
>>> .success(function (data) {
>>> metaData = data;
>>> deferred.resolve(data);
>>>
>>> })
>>> .error(function (data, status, header, config) {
>>> deferred.reject(status);
>>> });
>>> }
>>> return deferred.promise;
>>> };
>>>
>>>but I still got hit of my API controller's method twice. I'm going to look into Viv's idea now.
>>>
>>>>You need to return a promise even if you return the cached data.
>>>>
>>>>So define your deferred at the top of the code then to return the cached data:
>>>>
>>>>
>>>>if (angular.isObject(metaData)) {
>>>> deferred.resolve(metaData);
>>>> return deferred.promise;
>>>>}
>>>>
>>>>
>>>>This way you get the same data back regardless of whether the data was returned from the AJAX call or from the cached data.
>>>>
>>>>You might want to read this:
>>>>
http://weblog.west-wind.com/posts/2014/Oct/24/AngularJs-and-Promises-with-the-http-Service>>>>
>>>>which explains some of the mechanics behind this...
>>>>
>>>>+++ Rick ---
>>>>>
>>>>
>>>>
>>>>Define your $q.defer() before the first call then deferred.resolve(metaData); return deferred.promise() with the cached data and return the promise in the if block.
>>>>
>>>>+++ Rick ---
>>>>
>>>>>Hi everybody,
>>>>>
>>>>>I have two pages in the same form that need to access the same data.
>>>>>
>>>>>Each of the pages is controlled by its own controller and both have this code in the init:
>>>>>
>>>>>
>>>>>invoicesService.getMetaData().then(function (data) {
>>>>> $scope.invoicesMetaData = data;
>>>>>
>>>>> });
>>>>>
>>>>>So, I want to somehow adjust the service code to not invoke the method twice. Here is what I attempted to do but it's not working:
>>>>>
>>>>>
>>>>>app.factory('invoicesService', ['$http', '$q', function($http, $q) {
>>>>>
>>>>> var metaData = null;
>>>>>
>>>>> var getMetaData = function () {
>>>>> if (angular.isObject(metaData))
>>>>> return metaData;
>>>>>
>>>>> var deferred = $q.defer();
>>>>> $http.get('/api/invoices/metadata')
>>>>> .success(function (data) {
>>>>> metaData = data;
>>>>> deferred.resolve(data);
>>>>>
>>>>> })
>>>>> .error(function (data, status, header, config) {
>>>>> deferred.reject(status);
>>>>> });
>>>>> return deferred.promise;
>>>>> };
>>>>>
>>>>>I still get 2 hits in my API controller. Do you see how should I change the above to avoid the second call after the first one was already made?
>>>>>
>>>>>Thanks in advance.