I have an angular directive that I'm using to place a button form. The template is hidden until the user needs to see it. It's a simple template that works by itself, but when I combine it into the larger form the template does not appear.
Here is the directive:
.directive('buttonToggle', function() {
return {
restrict: 'A',
scope: {
myBtnArr: "="
},
template: '<button ng-click="click()">{{ myBtnTxt[myBtnArr] }}</button>',
link: function(scope) {
scope.myBtnTxt = ["AND", "OR", "NOT"];
scope.click = function() {
scope.myBtnArr = (scope.myBtnArr < 2 ? scope.myBtnArr + 1 : 0);
}
}
};
});
Then the html that works:
<div button-toggle my-btn-arr=0></div>
And the html snippet that doesn't work:
<tr ng-show="rowsShown >= 2"><td>Search by:</td><td><div button-toggle my-btn-arr=0></div><select ng-model="selection2" ng-options="option.text for option in options"></select><input type="text" size="20" ng-model="queryF2"><ng-md-icon icon="add_circle_outline" style="fill:#a9a9a9" ng-click="addSearchField();"></ng-md-icon> <ng-md-icon icon="remove_circle_outline" style="fill:#a9a9a9" ng-click="removeSearchField();"></ng-md-icon></td></tr>
When I run this html in the larger partial (which is controlled by a controller unrelated to the template) I get this error:
Error: [$compile:nonassign] Expression '0' used with directive 'buttonToggle' is non-assignable!
So just wrap that template function in scope.$apply right? Nope. When I do that...
link: function(scope) {
scope.myBtnTxt = ["AND", "OR", "NOT"];
scope.click = function() {
scope.$apply ( function() {
scope.myBtnArr = (scope.myBtnArr < 2 ? scope.myBtnArr + 1 : 0);
})
}
}
I get this error:
Error: [$rootScope:inprog] $apply already in progress
So it's obviously a problem with incorrectly wrapping the scope, but not sure how to fix it. Any thoughts?
It looks like you don't want to create a two way binding for my-btn-arr
. If you just want to pass data to the directive instead of bind to an existing variable, read from the attribute argument of link
.
.directive('buttonToggle', function() {
return {
restrict: 'A',
scope: {},
template: '<button ng-click="click()">{{ myBtnTxt[myBtnArr] }</button>',
link: function(scope, elem, attr) {
scope.myBtnArr = attr.myBtnArr;
scope.myBtnTxt = ["AND", "OR", "NOT"];
scope.click = function() {
scope.myBtnArr = (scope.myBtnArr < 2 ? scope.myBtnArr + 1 : 0);
}
}
}
});
If you also want the possibility to pass a variable as input use $parse
.
// This won't work with an isolated scope, inherit from parent scope instead
scope : true,
link: function(scope, elem, attr) {
// this will evaluate the expression against the scope
scope.myBtnArr = $parse(attr.myBtnArr)(scope);
}
Now you can use the directive as
<div button-toggle my-btn-arr="0"></div>
<div button-toggle my-btn-arr="view.myValue"></div>
If you really want to use a two way binding, it must be possible to write values back into the path defined with the expression my-btn-arr
. So, if you use scope: { myBtnArr: "=" }
you have to use the directive with a writeable expression like this:
<div button-toggle my-btn-arr="view.myValue"></div>
<!-- "0" is not assignable-->
<div button-toggle my-btn-arr="0"></div>
Examples: http://jsfiddle.net/Lw7ckt9x/1/
Rather than using the link function, try doing the same thing under the controller function. Link function is required when you are doing any DOM manipulation for the functionality you require controller should be sufficient.
Look at this error on the ngdocs.
You use this:
<div button-toggle my-btn-arr=0></div>
but 0
is not assignable. Meaning you cannot do 0 = 1;
You have to pass a variable with value of 0
instead of plain 0
Like this:
<div button-toggle my-btn-arr="obj.myvar"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With