bjudson
bjudson

Reputation: 4083

AngularJS directive using multiple services

UPDATE

My controller loads data from two services, and the directive is linked before one of the services has returned data. So I think I need to find a way to prevent loading the directive until the variable from the second service has actually been populated.

What is the best way to handle that?

Original question:

I have a scope with an array of objects, and also a single integer. So, in the controller, something like this:

$scope.array = [
    {title: 'foo', first: 'spam', second: 'eggs'}, 
    {title: 'bar', first: 'maps', second: 'sgge'}
];
$scope.another = 400;

I am using ngRepeat to pass values from each object in the array to a directive, like so:

<div ng-repeat="a in array" 
     my-directive="a.title" 
     my-first-val="a.first" 
     my-second-val="a.second"></div>

I would also like to bind another value, which is the same for all instances of the directive, but may also change:

<div ng-repeat="a in array" 
     my-directive="a.title" 
     my-first-val="a.first" 
     my-second-val="a.second"
     another-val="another"></div>

This final value never seems to bind properly [actually, it didn't bind because it hadn't populated yet - the syntax used here is fine]. Is this possible? Is there another way to bind a single value to all instances of a directive using ngRepeat?

Upvotes: 1

Views: 494

Answers (4)

saintmac
saintmac

Reputation: 589

To answer your updated question, I suggest you to use a $q promise. You could use a promise for loading the data of each service, and then the all method to combine the 2.

var promise1 = arrayService.getArray();
var promise2 = anotherService.getAnother();
var promise = $q.all([promise1, promise2]);
promise.then(function(data) {
  $scope.array = data[0];
  $scope.another = data[1];
});

EDIT: I understand from your comment that you want to know how to return a promise with a service. Code in 'arrayService' service

angular.module('yourApp').service('arrayService', function($q, someAsyncService) {
  this.getArray = function() {
    var deferred = $q.defer();
    someAsyncService.get(function(err, data){
      if (err) {
        deferred.reject(err);
      }
      else {
        deferred.resolve(data);
      }
    });
    return deferred.promise;
  };

});

Upvotes: 4

Warrenn enslin
Warrenn enslin

Reputation: 1036

in response to the updated question one approach you could take if you have access to the directive and can change it is to add a scope.$watch to the another-val attribute in the link or controller function

            scope.$watch('anotherVal', function(newVal) {
                //do something here...
            });

Upvotes: 0

Warrenn enslin
Warrenn enslin

Reputation: 1036

You might want to try to use expression evaluation with double braces

<div ng-repeat="a in array" 
 my-directive="a.title" 
 my-first-val="a.first" 
 my-second-val="a.second"
 another-val="{{another}}"></div>

angular would then try to evaluate the expression from the $scope instead of looking for the another variable from within the child scope created by ng-repeat

Upvotes: 0

saintmac
saintmac

Reputation: 589

ng-repeat creates a child scope, so you're another is different in every child scope. I would try defining another as the property of an object:

$scope.whatever.another = 400

html:

<div ng-repeat="a in array" 
 my-directive="a.title" 
 my-first-val="a.first" 
 my-second-val="a.second"
 another-val="whatever.another"></div>

Upvotes: 2

Related Questions