简体   繁体   中英

Access Angular Factory from Directive Scope

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>

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM