0

I have built a factory called "Data". I can use this in a controller as follows:

controller

myApp.controller('MyController', ['$scope', '$firebase', 'Data', function($scope, $firebase, Data) {

// OTHER REFS/FIREBASE

$scope.entries = Data;

}]);

index.html

<div ng-repeat="entry in entries">
{{entry.name}}
</div>

factory

myApp.factory('Data', ['$http', function ($http) {

    // load the data
    var entriesz = [];
    $http.get('data/main.json').success(function(data) {
      angular.forEach(data.ParkingFacilities, function(entry) {
         $http.get(entry.staticDataUrl).success(function(data) {
            entriesz.push(angular.extend(entry, data.parkingFacilityInformation));
         });
      });
    });

    //window.alert("Data Imported :" + entriesz.length);
    //window.alert(JSON.stringify(entriesz))

    return entriesz;
    // parse it and store it on firebase

}]);

I am now wondering how I can use this factory to update it in my firebase storage, and to create an additional controller that can access this stored data.

P.s. In case you were wondering why I dont use the factory like in the example above; basically it takes much computational time to retrieve the Data, so to save some computational time I want to split up the back-end and front-end processes.

WJA
  • 6,676
  • 16
  • 85
  • 152
  • 1
    Please edit the post to include the code for the Data factory, at least the minimal part of it that allows us to understand your problem. – Frank van Puffelen Dec 05 '14 at 16:23
  • Included the factory. Have a lot of difficulty working with the entriesz... typeof is undefined and the length of the array is apparently 0. However, when I put in $scope.entries = entriesz and then go back to my index.html and write {{entries[0]}} then it displays the object in my first array item. But it seems that in the controller entriesz[0] does not work... which is weird! – WJA Dec 05 '14 at 16:28

1 Answers1

2

It is hard to say with certainty, but it seems like you are being bitten by the asynchronous nature of $http.get.

Let's simplify your code a bit, to this:

/* 1 */ var entriesz = [];
/* 2 */ $http.get('data/main.json').success(function(data) {
/* 3 */   angular.forEach(data.ParkingFacilities, function(entry) {
/* 4 */      $http.get(entry.staticDataUrl).success(function(data) {
/* 5 */         entriesz.push(angular.extend(entry, data.parkingFacilityInformation));
/* 6 */      });
/* 7 */   });
/* 8 */ });
/* 9 */ window.alert("Data Imported :" + entriesz.length);

I've numbered the lines so we can refer to them more easily.

You seem to expect that this code executes linearly, so line 1, line 2, line 3... line 9. But that is not what happens. Each of those $http.get calls starts downloading data from a remote server. And since that may take quite some time, the browser doesn't wait for the data to come back. It simply continues to execute the rest of the code. Then when the response from the server comes back, it executes the callback function that you passed into success.

So the more likely execution order of your code is: 1, 2, 9... waiting for main.json... 3, 4... waiting for the data.... 5, 3, 4... waiting for data... 5, etc. Knowing this, you can probably see why entriesz.length is showing up as 0 in line 9: the entries haven't been loaded yet when you alert.

This is easier to see if you take those anonymous functions out of the flow and give them names like this:

var entriesz = [];
$http.get('data/main.json').success(onMainJsonLoaded);
window.alert("Data Imported :" + entriesz.length);

function onMainJsonLoaded(data) {
  angular.forEach(data.ParkingFacilities, function(entry) {
     $http.get(entry.staticDataUrl).success(onStaticDataLoaded);
  }
}

function onStaticDataLoaded(data) {
  entriesz.push(angular.extend(entry, data.parkingFacilityInformation));
  window.alert("Partial data imported :" + entriesz.length);
}

This asynchronous loading is a completely normal part of the modern web, but highly counter-intuitive to those new to it. It may be your natural instinct to try and circumvent it, but I urge you to not try that and instead just accept it. You cannot make the web synchronous (nor would anyone be happy about it if you could), so your best bet is to learn to deal with its asynchronous nature.

In this case, you do that by updating your UI as data becomes available. For example: I added an alert to the onStaticDataLoaded function above, to show that part of your data has become available at that time. This would be the perfect time to update a "{{x}} items are loaded" indicator in your web page.


I tried explaining the problem in the context of your question above. But there are plenty of (probably better) answers to similar questions already. Some of those might be worth your time, so I'll list them:

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thank you again. Tried your example but still does not work. It returns again the length to be equal to 0, and also seems not to enter the onStaticDataLoaded function. I added insided onMainJsonLoaded(data) the function entriesz.lengths and it again returned Undefined... – WJA Dec 06 '14 at 10:27
  • This is how my main.json looks like: https://npropendata.rdw.nl/parkingdata/v2/ and one of the staticDataUrls: https://npropendata.rdw.nl/parkingdata/v2/static/d8f4e169-b645-40e8-bb53-394d50d46a69 – WJA Dec 06 '14 at 10:28
  • 1
    My code snippet doesn't have a `return` statement. If yours still does, chances are you are still returning before the data is returned from the server. Update your question to include the new snippet. Please remove anything that is not directly relevant to the problem, just like I did when I wrote the snippets above. – Frank van Puffelen Dec 06 '14 at 13:34