7

All my directives use the same scope and I want my directives to operate by their own.

Directive:

app.directive('headerSort', function () {
    return {
        restrict: 'A',
        controller: function ($scope, $element, $attrs) {
            $scope.caption = $attrs.caption;

            $scope.doSort = function () {
                $scope.orderField = $attrs.headerSort;
                $scope.reverse = !$scope.reverse;
            };
        },
        template: '<div data-ng-click="doSort();">' +
                    '{{caption}}' +
                    '<i class="icon-sort"></i>' +
                  '</div>'
    };
});

Html:

<th data-header-Sort="FullName" data-caption="Full name"></th>
<th data-header-Sort="FirsName" data-caption="First name"></th>
<th data-header-Sort="Age" data-caption="Age"></th>

The result is that all the columns has the value 'Age' and sort by Age. I want of course that every column sort it's own column. How can I achieve this?

UPDATE: Forgot to mention that orderField and reverse are used in the ng-repeat | orderBy:

<tbody id="customerRows" data-ng-repeat="customer in customers | orderBy:orderField:reverse">
Castro Roy
  • 7,623
  • 13
  • 63
  • 97
Martijn
  • 24,441
  • 60
  • 174
  • 261

2 Answers2

11

Each instance of your directive needs to have its own caption, sort type, and reverse property. So the directive will need its own (child) scope — either an isolate scope (scope: {}) or a new scope (scope: true). Since the directive is not a standalone/self-contained component, I would not use an isolate scope (see also When writing a directive in AngularJS, how do I decide if I need no new scope, a new child scope, or a new isolated scope?).

With the type of scope selected for the directive, the sort type and reverse values can be passed to the parent via function arguments, or they can be set on parent scope directly. I suggest function arguments:

app.directive('headerSort', function () {
    return {
        scope: true,   // creates a new child scope
        link: function (scope, element, attrs) {
            scope.caption  = attrs.caption;
            scope.sortType = attrs.headerSort;
            scope.reverse  = false;
        },
        template: '<div data-ng-click="reverse=!reverse; doSort(sortType, reverse);">' +
             '{{caption}}</div>'
    };
});
function MyCtrl($scope) {
    $scope.orderField = "FirstName";
    $scope.reverse    = false;
    $scope.customers  = [ {FirstName: 'Martijn', Age: 22}, {FirstName: 'Mark', Age: 44}];
    $scope.doSort = function (sortType, reverse) {
        console.log('sorting',sortType, reverse);
        $scope.orderField = sortType;
        $scope.reverse    = reverse;
    };
}
<table>
    <th data-header-sort="FirstName" data-caption="First name"></th>
    <th data-header-sort="Age" data-caption="Age"></th>
    <tbody id="customerRows" data-ng-repeat="customer in customers | orderBy:orderField:reverse">
        <tr><td>{{customer.FirstName}}<td>{{customer.Age}}
    </tbody>
</table>

fiddle In the fiddle, just for simplicity, I did not include the FullName column.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
1

You need to "isolate" your scope. This will give each instance of the directive its own scope. Add the following to your directive definition:

scope: {},

So, your final directive definition would look like this:

app.directive('headerSort', function () {
    return {
        restrict: 'A',
        scope: {},
        controller: function ($scope, $element, $attrs) {
            $scope.caption = $attrs.caption;

            $scope.doSort = function () {
                $scope.orderField = $attrs.headerSort;
                $scope.reverse = !$scope.reverse;
            };
        },
        template: '<div data-ng-click="doSort();">' +
                    '{{caption}}' +
                    '<i class="icon-sort"></i>' +
                  '</div>'
    };
});

The Egghead.io videos go in to scope isolation in depth. You can view them here: http://www.egghead.io/

The isolated scope videos start at tutorial #16.

DigitalZebra
  • 39,494
  • 39
  • 114
  • 146
  • Thanx. The column names are no correctly shown, but the click still doesn't work. If it makes it easier, I don't casre where the doSort is located. In the controller scope or the directive's controller scope. – Martijn May 31 '13 at 13:56
  • `$scope.orderField` will set a property on the isolate scope, not the parent scope, so this won't work. – Mark Rajcok May 31 '13 at 14:59
  • You are right Mark, you would probably be better off using child scope. – DigitalZebra May 31 '13 at 23:27