2

I've been playing with Angular and I've moved from working with local data (which seems to work fine) to trying to populate my view from an ajax call in my factory.

Here's the code:

    <html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.min.js"></script>
</head>
<body>
<div ng-app="testApp">
  <h2>Get data using a Factory</h2>
    <div ng-controller="simpleController">

    <input type="text" placeholder="Filter" ng-model="name">

    <ul>
      <li ng-repeat="person in family | filter:name">[{{$index + 1}}] {{person.name}} - {{person.age}}</li>
    </ul>

  </div>
</div>
<script>
// our very, very simple controller - on the page itself
var testApp = angular.module('testApp', []);

testApp.factory('simpleFactory', function($http) {
  var family = [
    {name: 'Joe', age: 40},
    {name: 'Maryellen', age: 37},
    {name: 'Isaac', age: 12},
    {name: 'Emilie-Alice', age: 14}
  ];

  var factory = {};
  factory.getFamily = function() {
    return family;
  }

  factory.getFamily2 = function() {
    $http.get('/family.json').then(function(result) {
      family = result.data;
      console.log(family); // I see the objects! 
      return family; // this doesn't return the data like getFamily() does - why???
    });
  }

  return factory;
});

testApp.controller('simpleController', function($scope, simpleFactory) {
  $scope.family = [];

  init();

  function init() {
    $scope.family = simpleFactory.getFamily2();
  }
});
</script>
</body>
</html>

Everything seems okay, I can see the json data in my console log, but "return family" doesn't get the data to $scope.family

What am I missing? I know it has to be something simple.

Thanks!

sitesbyjoe
  • 1,861
  • 15
  • 21
  • Does simpleFactory have a value? Are you injecting the factory correctly? testApp.controller('simpleController' 'simpleFactory, function($scope, simpleFactory) – jcc Aug 06 '14 at 02:50

3 Answers3

2

To completely abstract the data handling into the factory, you can both return the promise from $http and leave the return inside the .then():

factory.getFamily2 = function() {
    return $http.get('/family.json').then(function(result) {
      family = result.data;
      console.log(family); // I see the objects! 
      return family; // this doesn't return the data like getFamily() does - why???
    });
  }

function init() {
    simpleFactory.getFamily2().then(function(data){
        $scope.family = data;
    }); 

This ensures the controller calling the factory method will get the data when it's ready. You can also handle error checking, etc, inside the factory and not in the controller, completely separating concerns.

TrazeK
  • 838
  • 1
  • 8
  • 18
  • Looking at the 2 above methods, which is the better way to go? It seems like removing the extra then() is cleaner, but it looks like more code ends up in the controller. Thoughts? – sitesbyjoe Aug 06 '14 at 04:42
  • I prefer to keep my controller clean of as much "work" as possible. I'd rather have the controller react to having the data than getting a promise and having to handle the error case. It's completely up to the author however. The solution I gave returns the resolved promise back to the controller, complete with the data. That's why `.data` isn't necessary in the controller. Good luck! – TrazeK Aug 06 '14 at 04:45
  • Thank you for the insight. This opens a ton of doors for now, thank you. – sitesbyjoe Aug 06 '14 at 04:47
2

The answer of sitesbyjoe is fine, but... you don't need the first assignation in controller (line 2 of 2nd block code), only calling to the function and assign a value inside is enogh

Factory

factory.getFamily2 = function() {
    return $http.get('/family.json').then(function(result) {
      family = result.data;
      return family;
    });
  }

In Controller

 function init() {
    simpleFactory.getFamily2().then(function(data) {
        $scope.family = data;
    });
  }
jjalonso
  • 691
  • 5
  • 17
0

FYI - What I ended up changing in the factory:

factory.getFamily2 = function() {
    return $http.get('/family.json').then(function(result) {
      family = result.data;
      return family;
    });
  }

and in the controller:

function init() {
    $scope.family = simpleFactory.getFamily2().then(function(data) {
        $scope.family = data;
    });
  }

With these changes in place I get the remote data, the view filtering works fine, and all is well.

sitesbyjoe
  • 1,861
  • 15
  • 21