Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Template Not Showing with ng-hide

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?

like image 690
Dave Kanter Avatar asked Jan 09 '16 20:01

Dave Kanter


3 Answers

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/

like image 146
hansmaad Avatar answered Nov 18 '22 19:11

hansmaad


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.

like image 5
Deepak Sharma Avatar answered Nov 18 '22 17:11

Deepak Sharma


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>
like image 2
koox00 Avatar answered Nov 18 '22 19:11

koox00