I would go with your EDIT #2 because they are related. If we create them as separate elements, we need to somehow pass the related element to each one => When we click on 1 button, we update itself and also the related element.
Here I modified your first approach to make it work: http://plnkr.co/edit/KgYIlATiw9xzTEZt9Jv1?p=preview
In this example, I have to pass the related element to each directive so that when we click we can update itself and the related element:
related-element="btnForward"
I did some modifications in the directive:
scope: {
reactOn: "=", //use property binding instead of function binding
relatedElement:"@"
},
link: function(scope, element, attrs) {
scope.toggle = function(){
scope.reactOn = !scope.reactOn;//toggle current element
var relatedScope = $("#"+scope.relatedElement).scope();//get related element's scope and toggle it
relatedScope.reactOn = !relatedScope.reactOn;
}
//var cattr = attrs.ngDisableReactOn;
element.attr("ng-class", "{'disabled': !reactOn}"); //Use reactOn instead as this is the property of current scope
element.attr("ng-disabled", "!reactOn");
element.attr("ng-click", "toggle()");
element.removeAttr("ng-disable-react-on");
$compile(element)(scope);
}
We don't need to make things complex. Just create a normal directive to wrap 2 buttons.
myApp.directive("ngDisableReactOn", function($compile) {
return {
restrict: "A",
templateUrl:"ngDisableReactOn.html",
scope: {
can_go_back: "@"
},
link: function(scope, element, attrs) {
scope.goBack = function(){
scope.can_go_back = false;
}
scope.goFwd = function(){
scope.can_go_back = true;
}
}
}
});
Template:
<input type="button" value="go back" ng-click="goBack()" ng-class="{'disabled': !can_go_back}" ng-disabled="!can_go_back">
<input type="button" value="go fwd" ng-click="goFwd()" ng-class="{'disabled': can_go_back}" ng-disabled="can_go_back">
DEMO
Another solution is to create a parent directive as a container. This is the solution I like the most. With this approach, you can freely change the inner content of the directive like adding more buttons, more text,....(DON'T NEED TO HARDCODE THE TEMPLATE) The parent directive works as a manager to ensure there is only 1 active child at a time:
myApp.directive("ngDisableReactOnContainer", function() { //Container directive to manage all child directives
return {
restrict: 'EA',
replace: true,
transclude: true,//Use transclusion to move inner content to the template
template: '<div ng-transclude></div>',
controller: function() {
var children = [];
this.selectChild = function(activeChild) { //ensure that only 1 child is active at a time
activeChild.active = true;
angular.forEach(children, function(child) {
if (child != activeChild) {
child.active = false;
}
});
}
this.addChild = function(child) {
children.push(child);
}
}
};
});
myApp.directive("ngDisableReactOn", function($compile) {
return {
restrict: "A",
scope:{
active:"@"
},
require: '^?ngDisableReactOnContainer',
link: function(scope, element, attrs, controller) {
scope.active = scope.active === 'true';
controller.addChild(scope);//register itself with the container
scope.select = function(){//When this element is clicked, inform the container to toggle all children accordingly.
controller.selectChild(scope);
}
//Add ng-class and ng-disabled based on your requirement.
element.attr("ng-class", "{'disabled': active}"); //Use active instead as this is the property of current scope
element.attr("ng-disabled", "active");
element.attr("ng-click", "select()");
element.removeAttr("ng-disable-react-on");
$compile(element)(scope);
}
}
});
Using these directives would be simple:
<div ng-disable-react-on-container>
<input ng-disable-react-on type="button" value="button 1" active="true" >
<input ng-disable-react-on type="button" value="button 2" >
<input ng-disable-react-on type="button" value="button 3" >
</div>
DEMO