2

I have a directive that calculates the position of the clicked element from a grid and gets positioned in place.

So far the directive appears where is it supposed to, but I'm attempting to trigger a $http call to populate the directive (one call for each element clicked) and so far I had no luck.

You can see the directive code here:

angular.module('myApp')

  .directive('theDirective',  [function() {
  return {
    restrict: 'A',
    scope: { position: '@', last: '@', release: '='},
    link: function(scope, element, attrs) {

      element.bind('click', function() {

        // Makes http call to get versions

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

        // Highlight clicked element
        angular.element(document.querySelector('.clicked')).removeClass('clicked');
        element.addClass('clicked');
        // Create the collapse element or select existing one
        var collapseQuery = document.querySelector('#collapse');
        var collapse = collapseQuery === null ?
          angular.element('<div id="collapse" class="col-md-12 col-xs-12"> \
                <div class="inner"> \
                  <ul> \
                    <li class="title">{{release.title}}</li> \
                    <li class="row top" ng-show="versions"> \
                      <div class="col-md-1">Year</div> \
                      <div class="col-md-3">Format</div> \
                      <div class="col-md-3">Label</div> \
                      <div class="col-md-2">Country</div> \
                      <div class="col-md-2">Cat. Nº</div> \
                    </li> \
                    <li class="row" ng-show="versions" ng-repeat="version in versions | filter: \'!file\' | orderBy: version.released"> \
                      <div class="col-md-1">{{(version.released | release:4) || \'-----\'}}</div> \
                      <div class="col-md-3">{{version.format}}</div> \
                      <div class="col-md-3">{{version.label}}</div> \
                      <div class="col-md-2">{{version.country}}</div> \
                      <div class="col-md-2">{{version.catno}}</div> \
                    </li> \
                    <li class="row top" ng-hide="!release.format"> \
                      <div class="col-md-1">Year</div> \
                      <div class="col-md-3">Format</div> \
                      <div class="col-md-3">Label</div> \
                    </li> \
                    <li class="row" ng-hide="!release.format"> \
                      <div class="col-md-1">{{release.year}}</div> \
                      <div class="col-md-3">{{release.format}}</div> \
                      <div class="col-md-8">{{release.label}}</div> \
                    </li> \
                  </ul> \
                </div> \
              </div>') :
          angular.element(collapseQuery);

        // Based on the position of the clicked element calculate the rounded number up to the nearest multiple of four
        var calculatedPosition = Math.ceil(scope.position / 4) * 4;

        // Get the element at the calculated position or the last one
        var calculatedQuery = document.querySelector('[position="' + calculatedPosition + '"]');
        if (calculatedQuery === null) calculatedQuery = document.querySelector('[last="true"]');;

        var calculatedElement = angular.element(calculatedQuery);

        // Insert the collapse element after the element at the calculated position
        calculatedElement.after(collapse);

        // Highlight the calculated element
        angular.element(document.querySelector('.calculated')).removeClass('calculated');
        calculatedElement.addClass('calculated');
      });

      scope.$on('$destroy', function() {
        element.unbind('click');
      });


    }
  };
}
]);

I also made a Plunker.

Any pointers on which direction should I take?

2 Answers 2

2
+50

You are attempting to use $http in the directive without injecting it as a dependency. It should be included using inline injection annotation, like this:

angular.module('myApp').directive('theDirective', function($http) {...

Your $http call makes use of the release scope property,

$http.get('http://api.discogs.com/masters/' + scope.release.id + '/versions').

but (at least in your plunkr) you didn't include it in the directive element tag. Add it like this:

<div the-directive release="release" ng-repeat="release in releases...

Finally, your directive displays the results of the $http call in a dynamically created element. To achieve binding in this element, you need to compile it. So add $compile to the list of directive dependencies:

angular.module('myApp').directive('theDirective', function($http, $compile) {...

When you are finished manipulating the DOM, compile the element:

var collapse = angular.element('<div>' ...
...
$compile(collapse)(scope);

I fixed a few other things, but they don't really relate to using $http in a directive. Here is a working plunker: http://plnkr.co/ttV0ZowaL8Tyz1hAkZak

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

3 Comments

Hi there! You solution is populating the directive, but for whatever reason, once a release is clicked and the results displayed, those same results will populate the following clicks (it doesnt update to the new info retrieved), and it also gets duplicated (eg: first call results are release with name EXAMPLE, version A, B and C, when I click to another release, results display release name EXAMPLE (doesnt update release.name) and version A, A, A, B, B, B, C, C, C. Any idea why this is happening?
try it now. i suspect it had to do with trying to reuse the existing collapse element. i updated the plunker to recreate it each time, and i don't see the problem now.
Works brilliantly now. I've also created a conditional for the cases where the http comes back 404, and it integrates perfectly. Thanks!
1

I think you are trying to do too much in your directive. I would handle all your events on your controller, and ajax calls in a service.

As for your markup I would nest is as follows

artists
    releases
        release info

You can toggle the visibility status of each layer within your controller and load the necessary data when needed.

Then I would include a very basic directive to handle the positioning and only the positioning of the release details.

Comments

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.