0

I'm trying to set the value of a directive's attribute by calling a function on the containing page's controller, but it doesn't work as expected. In the code below, the "make" object does not have a "modelList" property, so I must place a separate call to the server to get it for each make.

<div ng-repeat="make in makeList">
  <model-list-directive model-list="getModelList(make)" />
</div>

app.controller("myController",function($scope) {
  $scope.getModelList = function(make) {
  return null;
  //return myService.getModelList(make);
 };
})

app.directive("modelListDirective",function() {
  restrict:'E',
  scope: {
    modelList: '='
  },
  template: '<ul><li ng-repeat="model in modelList">{{model.modelName}}</li></ul>',
  controller: ['$scope', function ($scope) {
  }]

If the getModelList() function is set to return null (not commented out in the code), no error is given, but the function is called multiple times (randomly varies between 3 and 5 usually).

The real problem comes when I invoke myService.getModelList(make) (commented out in the code). This results in an endless loop of calls to the service, which crashes the browser.

I'm guessing this is because of two-way binding, but I'm not sure.

Is there a better way to get dynamic data to the directive?

1 Answer 1

1

I think part of the problem is that your directive definition isn't returning an object. It should look like this:

app.directive('modelListDirective',function() {
    return { // <-- need to return an object
        restrict:'E',
        scope: {
            modelList: '='
        },            
        template: '<ul><li ng-repeat="model in modelList">{{model.modelName}}</li></ul>',
        controller: ['$scope', function ($scope) {
        }]
    };
});

However, you're passing a function as a 2-way binding into the directive, which you shouldn't do. See this answer to a similar issue.

What you can do instead is inject myService directly into your directive, then have your directive call myService.getModelList() in its link function.

So your markup would look like this:

<div ng-repeat="make in makeList">
  <model-list-directive make="{{make}}" />
</div>

Each directive instance would just need the make.

And your directive definition would look like this:

app.directive('modelListDirective', ['myService', function(myService) {
    return {
        restrict:'E',
        scope: {
            make: '@'
        },
        link: function (scope, element, attrs) {
            scope.modelList = myService.getModelList(scope.make);
        },
        template: '<ul><li ng-repeat="model in modelList">{{model.modelName}}</li></ul>',
        controller: ['$scope', function ($scope) {
        }]
    };
}]);

setting scope.modelList in its link function.

Here's a fiddle.

Sign up to request clarification or add additional context in comments.

1 Comment

Mike, thanks for the input, especially the link discussing the infinite loop. I'll go ahead and code it to pass the function to the directive instead of the desired function result. For those who happen upon this solution, my specific project involves a directive that is used in multiple ways, sometime to display a list of 'models' associated with a 'make', sometimes to display a random list of 'models'. Handling the second instance is easy, as the directive is used only once on the page. However, the first instance is placed in a repeater, requiring dynamic generation of the model lists.

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.