I've been working on this issue for two days now. I get the feeling it should be a lot simpler.
Problem Description
I'd like to create a directive that is used as follows:
<my-directive ng-something="something">
content
</my-directive>
and has as output:
<my-directive ng-something="something" ng-more="more">
content
</my-directive>
Naturally it would have a linking function and controller that do some work, but the main concerns are:
- that the DOM element keeps the original name, so that intuitive css styling can be applied,
- that attribute directives already present keep working properly, and
- that new attribute directives can be added by the element directive itself.
Example
For example, say I want to create an element that does something internally when it is clicked on:
<click-count ng-repeat="X in ['A', 'B', 'C']"> {{ X }} </click-count>
which could compile into something like this:
<click-count ng-click="internalFn()"> A </click-count>
<click-count ng-click="internalFn()"> B </click-count>
<click-count ng-click="internalFn()"> C </click-count>
where internalFn
would be defined in the internal scope of the clickCount
directive.
Attempt
One of my attempts in is this Plunker: http://plnkr.co/edit/j9sUUS?p=preview
Since Plunker seems to be down, here's the code:
angular.module('app', []).directive('clickCount', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
ccModel: '='
},
compile: function(dElement) {
dElement.attr("ngClick", "ccModel = ccModel + 1");
return function postLink($scope, iElement, iAttrs, controller, transclude) {
transclude(function(cloned) { iElement.append(cloned); });
};
},
controller: function ($scope) {
$scope.ccModel = 0;
}
};
});
This is some HTML using the directive:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app">
<hr> The internal 'ng-click' doesn't work:
<click-count ng-repeat="X in ['A', 'B', 'C']" cc-model="counter">
{{ X }}, {{ counter }}
</click-count>
<hr> But an external 'ng-click' does work:
<click-count ng-repeat="X in ['A', 'B', 'C']" cc-model="bla" ng-init="counter = 0" ng-click="counter = counter + 1">
{{ X }}, {{ counter }}
</click-count>
<hr>
</body>
</html>
And because the element keeps its name, css can be used as follows:
click-count {
display: block;
border: solid 1px;
background-color: lightgreen;
font-weight: bold;
margin: 5px;
padding: 5px;
}
I have several ideas on what might be wrong with it, but I've tried a number of alternative approaches. If I mess around in the linker, perhaps try to $compile
again, the controller function has to be called twice too. Anyway, an example of how to do it properly would be most appreciated.