1

I have a function that makes a $http call to an external API and then populates some results within an ng-repeat array.

Right now the function gets triggered on every element on the ng-repeat, which creates a whole lot of server calls. I'd like for the function to only make the call once an element from the ng-repeat is clicked upon.

I've tried with ng-click, but i'd say i'm missing something.

The $http query that i'm trying to call on click is the second one:

function ImageCtrl($scope, $http) {
      $scope.image = 'img/record-default.png'; 
      $http.get('http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=e8aefa857fc74255570c1ee62b01cdba&artist=' + $scope.artist.name + '&album=' + $scope.release.title + '&format=json').
        success(function (data4) {
          $scope.image = data4.album.image[2]['#text'];
        }
      )

    function getVersions ($scope, $http){    
      $http.get('http://api.discogs.com/masters/' + $scope.release.id + '/versions').
        success(function (data5) {
          $scope.versions = data5.versions;
      });
  }   

}

And the relevant html:

<div class="col-md-3" ng-controller="ImageCtrl" ng-repeat="release in releases | filter:album | filter:year | filter:{ role: \'main\' }" > 
  <div class="release" ng-click="getVersions()"> \
     <img class="img-responsive" ng-src="{{image}}" /> {{release.title}} 
        <ul ng-controller="ImageCtrl">
           <li ng-repeat="version in versions">{{version.format}}</li>
        </ul>            
  </div> 
</div>

And a working Plunker. Function in question is line 60 on script.js

10
  • May be I have understood the questions wrong. Why wouldn't you just move ng-click='getVersions()' to li? Commented Mar 21, 2014 at 0:43
  • 1
    Is that Plunkr complete? It doesn't look like you are even registering your controllers. Commented Mar 21, 2014 at 1:29
  • 1
    @EricMitjans - Ok. So... not to get you down but there are a whole bunch of things wrong with your implementation. Give me a little bit of time and I'll refactor your Plunkr. Going to be longer than 5 minutes ;) Commented Mar 21, 2014 at 1:35
  • 1
    @EricMitjans - I'm working through it now. Should help me pinpoint issues with the code. Commented Mar 21, 2014 at 1:44
  • 1
    @EricMitjans - Here is the fully refactored Plunkr plnkr.co/edit/6R3zEX?p=preview Commented Mar 21, 2014 at 4:59

1 Answer 1

2

So I ended up taking what you have shown and doing some refactoring.

I moved getVersions to the prototype, and use it to append versions to a release object instead of the $scope.

function ImageCtrl($scope, fakeService) {
  var _this = this;
  this.fakeService = fakeService;
  this.$scope = $scope;

  fakeService.getReleases()
      .then(function (releases) {
      $scope.releases = releases;
  });

  this.$scope.getVersions = function(release){
      _this.getVersions(release);
  };
}

ImageCtrl.$inject = ['$scope', 'fakeService'];

ImageCtrl.prototype.getVersions = function (release) {
  this.fakeService.getVersions(release.id)
      .then(function (versions) {
      release.versions = versions;
  });
};

The markup isn't terribly different, but you can see where I pass the actual release object into the getVersions function in the click event. This way it always acts directly on the object bound to that particular row.

<div class="row" ng-controller="ImageCtrl">
    <div class="col-md-3" ng-repeat="release in releases">
        <div class="release" ng-click="getVersions(release)">
            <h1>{{release.title}}</h1>
            <img class="img-responsive" height="100" width="100" ng-src="{{release.image}}" />
            <ul>
                <li ng-repeat="version in release.versions">{{version.format}}</li>
            </ul>
        </div>
    </div>
</div>

And here is a working demo showing the whole thing in action: http://jsfiddle.net/jwcarroll/k6mkt/

I'm using a fake service here to mimic calling a web service in order to get the data. I highly recommend wrapping up your calls to $http in order to encapsulate data access in your controller.

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

2 Comments

Well put Josh. I agree that one should encapsulate the data access layer, and love the idea of the fake service. However the delegation here is a bit strained in my opinion, and the code can get convoluted. It may be better to go all the way with refactoring and simply use an angular service dedicated for the purpose.
@EliranMalka - I actually did end up going all the way with the refactoring here: plnkr.co/edit/6R3zEX?p=preview That feels weird to say.

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.