Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them, it only takes a minute:

I'm trying to import JSON data into an angularJS application. I split my app into a controller and the import-service, but both in different files. I'm also using bower, grunt and yeoman (that's due to work, I'm not quite used to these, maybe there's also a problem.)

The strange behavior is:

I wanted to retrieve the JSON data with a $http.get() and resolve it - all within a service, so that I can hand out the data object from there to the main controller and won't have to resolve it there. Strangely, I didn't get any data, it was empty or not readable. Then I handed out the promise which I the $http.get() mehtod gives back and resolved it in the controller. That's not what I wanted, but now it works.... but why?

I guess it's a schmall misstake somehwere but neither me nor my team members can find one. Strangely, doing a little test-app without grunt, yeoman and bower it worked.

I'd appreciate every hint or idea... Jana

Here's my code from the NOT working version, first the main module with controller:

/** Main module of the application. */
(function () {
  'use strict;'
  angular.module('angularRegelwerkApp', [])
    .controller('RegelwerkCtrl', function ($scope, CategoryFactory) {

      $scope.categories = CategoryFactory.getCategories();
      $scope.subcategories = CategoryFactory.getSubCategories();

    }
  );
})();

Service-part:

(function () {
  'use strict';
  var app = angular.module('angularRegelwerkApp')
    .service('CategoryFactory',
    function ($http) {

      var categories = [];
      var subcategories = [];

      $http.get("../mockdata/categories.json").then(function (response) {
        categories = response.data;
      })
      $http.get('../mockdata/subcategories.json').then(function (response) {
        subcategories = response.data;
      })
      return {
        getCategories: function(){
          return categories;
        },
        getSubCategories: function(){
          return subcategories;
        }
      }
    }
  );
})();

Here's my code from the WORKING version, first the main module with controller:

/** Main module of the application. */
(function() {
  'use strict;'
  angular.module('angularRegelwerkApp', [])
    .controller('RegelwerkCtrl', function ($scope, CategoryFactory) {

      $scope.categories = [];
      $scope.subcategories = [];

      CategoryFactory.getCategories().then(function(response) {
        $scope.categories = response.data;
      });
      CategoryFactory.getSubCategories().then(function(response) {
        $scope.subcategories = response.data;
      });
    }
  );
}
)();

Service-part:

(function () {
  'use strict';
  var app = angular.module('angularRegelwerkApp')
    .service('CategoryFactory',
    function ($http, $q) {

      var categoryURL = "../mockdata/categories.json";
      var subcategoryURL = '../mockdata/subcategories.json';

      function getSubCategories() {
        return $http.get(subcategoryURL);
      }
      function getCategories() {
        return $http.get(categoryURL);
      }
      return {
        getCategories: getCategories,
        getSubCategories: getSubCategories
      }
    }
  );
})();
share|improve this question

3 Answers 3

up vote 1 down vote accepted

This is destroying your reference, so loop over the data from the server and push it into the variables you need:

  $http.get("../mockdata/categories.json").then(function (response) {
    for(var x = 0; x < response.data.length; x++){
        categories.push(response.data[x]);
    }
  });
share|improve this answer
    
okay... I want to try this. But how do I iterate over an unknown object'smproperties and filling the categories with them? With for (var property in responseData) I only got an increasing index number alerting the property. And how do i add a property to the categories? The JSON data is like a list of objects which have several properties... – Jana Nov 17 '14 at 12:45
    
I edited that in. – Mathew Berg Nov 17 '14 at 12:52
    
Thanks! It's really easy, my mind was a little blocked I think. AND it worked! very well. Thank you! – Jana Nov 17 '14 at 13:01
    
Still there is a question of understanding... why did it work when I resolved the promise in the controller? The code is the same as in my service (before correcting it), without any loop, but it worked fine. Do you know why? Is it just that it takes some milliseconds to be resolved and either passing it to the controller or looping over it is enough time for resolving? But why then isn't it "destroying the reference" in the controller? – Jana Nov 17 '14 at 13:39
1  
Because it's the same reference in the controller as you're directly modifying the variables attached to the scope object. In your service the arrays are not attached to an object and therefore you obliterate them when you reset them after the http post. – Mathew Berg Nov 17 '14 at 14:02

$http call is by default asynchronous.

So in your first version, when you write like $scope.categories = CategoryFactory.getCategories(); you get empty categories, since by the time you access categories, it may not have been loaded with response data.

your app flows like this -

  1. you load the controller
  2. you call the service
  3. service calls $http
  4. you try to access categories (but data will not be available until response is returned from server)
  5. $http.then loads data to $scope.categories
share|improve this answer
    
Strangely, in a test version without the framework things it worked... So if I want to capsulate the retrieve function in the service, what are you suggesting to do? Adding some wait-function comes to my mind but that seems like rather ugly hacking... – Jana Nov 17 '14 at 9:47
    
correct - wait function would be ugly. You can use $watch on scope variables to see if data has arrived from server and act accordingly. But your second version is clean and preferred. – Rabi Nov 17 '14 at 9:56
    
Well, maybe it's clean enough to work, but the function isn't cleanly separated like I wish it to be... :-( I'll see if $watch will help here, don't know this function so far. – Jana Nov 17 '14 at 10:11

You are storing your data in Angular primitives and these don't update. instead store all your data in an object and it shoudl work (you'll also need to update controller)

(function () {
  'use strict';
  var app = angular.module('angularRegelwerkApp')
    .service('CategoryFactory',
    function ($http) {

      var data = {};

      $http.get("../mockdata/categories.json").then(function (response) {
        data.categories = response.data;
      })
      $http.get('../mockdata/subcategories.json').then(function (response) {
        data.subcategories = response.data;
      })
      return {
        getCategories: function(){
          return data.categories;
        },
        getSubCategories: function(){
          return data.subcategories;
        }
      }
    }
  );
})();
share|improve this answer
    
Thanks for the suggestion, I'll try that and post whether it works! – Jana Nov 17 '14 at 9:51
    
Well, now I'm getting Error: $scope.categories is undefined - though I of course instanciated $scope.categories and used the not-working-code from above for my controller. O.ó Why that? I don't know... – Jana Nov 17 '14 at 10:02
    
You used $scope.categories = CategoryFactory.data.categories ? – Simon H Nov 17 '14 at 10:16
    
No. As you return data.categories in the service, I just used $scope.categories = CategoryFactory.getCategories() to get exactly the category property of the data object. – Jana Nov 17 '14 at 12:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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