1

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
      }
    }
  );
})();

3 Answers 3

2

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]);
    }
  });
Sign up to request clarification or add additional context in comments.

4 Comments

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...
Thanks! It's really easy, my mind was a little blocked I think. AND it worked! very well. Thank you!
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?
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.
1

$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

3 Comments

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...
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.
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.
0

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;
        }
      }
    }
  );
})();

4 Comments

Thanks for the suggestion, I'll try that and post whether it works!
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...
You used $scope.categories = CategoryFactory.data.categories ?
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.

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.