1

I'm pretty new to Angular, so maybe this isn't the best way to approach a problem. I'm trying to access a factory called Devices from a directive, called topDevices, scope.

topDevices.js:

app.directive('topDevices', function() {
    return {
        restrict: 'E',
        scope: {
            count: '@',
            sortKey: '@',
            devices: Devices.sortByKey(this.count, this.sortKey)
        },
        templateUrl: 'app/directives/topDevices.tpl.html'
    }
});

Is this something not normally allowed or just bad practice/approach? Devices contains a list of devices using Devices.all(), but I also have a Devices.sortByKey(count, key) function to return a limited set of devices sorted by a particular key.

EDIT: More info

The purpose of this is to create a template that could list, for example, the top 5 devices by some X metric. The template is this:

<h3>Top {{ count }} by {{ sortKey }}</h3>
    <table class="table table-bordered table-condensed table-striped table-hover">
        <tbody>
            <tr ng-repeat="device in devices">
                <td>{{ device.id }}</td>
                <td>{{ device.name }}</td>
                <td>{{ device[sortKey] }}</td>
            </tr>
            <tr ng-show="!devices.length">
                <td colspan="3">No device info available</td>
            </tr>
        </tbody>
    </table>
Andrew
  • 113
  • 1
  • 2
  • 8

1 Answers1

2

If this is an Angular factory you can pass it to the directive as a dependency:

app.directive('topDevices', function(Devices) {...})

This way you are decoupling from the concrete instance you are using

If on the other hand you want to be able to pass the sortByKey() method, and use it in the isolated scope of the directive you should defined a scope property with '&' or '=' value.

Using the ´=´ creates two way data binding, and it's the easiest to grasp:

 app.directive('topDevices', function() {
  return { 
    restrict: 'E', 
    scope: { 
        count: '@', 
        sortKey: '@',
        sort: '='
     }, 

    templateUrl: 'app/directives/topDevices.tpl.html'
     },
    link: function(scope) {
        scope.sort(scope.count, scope.sortKey);
    }

});

the link method of the directive is executed when it is created
Then where you use the directive:

<top-devices sort="ctrl.sortByKey"></top-devices>

ctrl is the controller from the controllerAs syntax, you can attach the factory's method to the controller like

// inside a controller
this.sortByKey = function(count, sortKey) {
     return Device.sortByKey(count, sortKey);
 } 

I'll try to explain using the '&':

app.directive('topDevices', function() {
return { 
    restrict: 'E', 
    scope: { 
        count: '@', 
        sortKey: '@',
        sort: '&'
     }, 

    templateUrl: 'app/directives/topDevices.tpl.html'
     },
    link: function(scope) {
        scope.sort({
            count: scope.count,     
            sortKey: scope.sortKey
        });
    }

});

As you can see the function is called in a different way -> passing an object which keys are the arguments names and their corresponding values

Then where you use the directive:

<top-devices sort="ctrl.sortByKey( count, sortKey)"></top-devices>

Note that this is not calling the function, because we used the '&' property definition

You can even use the sort function in the directive's html template:

topDevices.tpl.html

<div ng-show="sort({count: count, sortKey: sortKey})">
    <a href="#" ng-repeat...>{{something}}</a>
</div>

Not the brightest example but you get the point

Also you can check out this relevant answer

There is another way to pass the function like this

<top-devices sort="ctrl.sortByKey"></top-devices>

Then in the ´link´ function you can use it like this

{
     ...
    link: function(scope) {
         var unwrapped = scope.sort();
         unwrapped( scope.count, scope.sortKey); 
    }
}

Small side note - in your example you cannot access ´this.count´ and ´this.sortKey´ in the place you are using them:
1. They are not yet defined. 2. ´this´ doesn't refer the scope object.

Edit One way to achive you goal is by using a filter: check out this fiddle to see basic implementation. Or maybe there is already a built in filter that can help you do this. Filters can be combined:

<li ng-repeat="data in collection | filter1:arg | filter2:bar | filter1:foo></li>
Community
  • 1
  • 1
kidroca
  • 3,480
  • 2
  • 27
  • 44
  • Hi, my thow cents : you may pass the method réf inteed of calling it ==> "" – Rogerio Soares Aug 21 '16 at 23:56
  • When using '&' you have to reference it like this -> it isn't calling the method – kidroca Aug 22 '16 at 00:40
  • Thank you so much for the detailed explanation. I'm still having a tough time trying to grasp it all, but that's mostly because I'm so new to Angular. What I thought I could do was to just call `` and just be able to render the top 5 devices sorted by value of `keyName`. From the examples you've provided, it seems like a bit more coupling is involved between the controller and directive and I'm not sure I even get how `count` and `sortKey` get passed into the directive if they're not listed as attributes for ``. – Andrew Aug 22 '16 at 03:21
  • Glad I can help, from the additional information it sounds like you just need a filter. Check out my edit at the bottom – kidroca Aug 22 '16 at 22:04