Reputation: 7288
I've found that this is a useful pattern:
Widgets written as angular directives:
MyApp.directive('parentWidget', function () {
return {
controller: function ($scope) {
$scope.widgets = [{n: 1}, {n: 2}, {n: 3}];
}
};
});
MyApp.directive('childWidget', function () {
return {
scope: {myAttr: '@myAttr'},
controller: function ($scope) {
$scope.dynamicValue = function () {
return 'dynamic';
};
}
};
});
The parent widget is included in the page like this:
<table parent-widget></table>
The template of the parent widget looks like this:
<thead>
<tr>
<th>The Dynamic Column</th>
<th>The Static Column</th>
</tr>
</thead>
<tbody>
<tr child-widget
ng-repeat="w in widgets | orderBy:n"
my-attr="{{w.n}}">
</tr>
</tbody>
And the template of the child widget looks like this:
<td>{{ dynamicValue() }}</td>
<td>{{ myAttr }}</td>
My Question: How can I order the table on the dynamic value of the child widget? I am comfortable doing so on static values, as shown.
The only thing I can come up with is to use jquery to manipulate the <tr>
s after the fact, which is very un-angular.
EDIT: Some helpful commenters have confirmed my suspicion that this can't be done. So I guess my question is, what's the best way to restructure this pattern to allow for such sorting? I would prefer to continue to separate concerns, i.e. dynamicValue() is a concern of the child widget and the code should reflect that.
SOLVED: The accepted answer had several helpful clues. In particular, the use of bi-directional binding in the scope of the child directive and the advice to sort on the model, on on the DOM. I had to add a $watch
to make it happen, see below. I'd love to hear anyone's comments if they can improve on this.
Upvotes: 0
Views: 238
Reputation: 11317
The angular approach to the problem:
If you want to do it the angular way, then apply the sorting to the model and not to the <tr>
elements being already rendered into the page. The only place where the complete relevant part of the model is known, is the controller of the parent widget, and this is where the sorting has to happen.
Consequences:
To be able to sort, you will of course need access to the dynamic values generated by the directives, but this is not a problem because your directives can set the dynamic values within the fragment of the model they see. However, they have to be able to write the values into their widget object (model):
MyApp.directive('parentWidget', function () {
return {
controller: function ($scope) {
// init the dynamic values with null to make explicit that they
// are part of the model
$scope.widgets = [{n: 1, d: null}, {n: 2, d: null}, {n: 3, d: null}];
}
};
});
MyApp.directive('childWidget', function () {
return {
scope: {
myAttr: '@',
dynamicValue: '='
},
controller: function ($scope) {
// assign the function here or a static value. Whatever works best for you.
$scope.dynamicValue = function () {
return 'dynamic';
};
}
};
});
Of course, you then parameterize your directive like this in the template:
<tr child-widget
ng-repeat="w in widgets | orderBy:n"
my-attr="{{w.n}}"
dynamic-value="w.d">
</tr>
For my part, I would prefer to write the actual dynamic values into the model instead of a function that calculates it, but as indicated in the comment, both will work if you sort accordingly.
Upvotes: 1
Reputation: 28750
If you want to modify the children to be able to sort by them pass them through as objects not attributes.
<tr ... my-attr="w"></tr>
And
<td>{{ myAttr.dynamicValue }}</td><td>{{ myAttr.n }}</td>
jsfiddle: http://jsfiddle.net/4J2aw/
Upvotes: 1