I'm having trouble getting ng-show
to work inside my directive template. I'm using AngularJS 1.6.4. The Chrome debugger shows the successful change from ng-show="true"
to ng-show="false"
in the final DOM. But the element stays hidden when set to true. It appears this is because AngularJS adds a ng-hide
class to the list in the element, but does not remove this when ng-show
changes to true. Maybe AngularJS does not evaluate at this stage? How do I get this to show/hide properly?
I've been playing around with this for a while and have tried may different approaches including using the loading
parameter directly instead of using the scoped showspinner
. I've also tried omitting the mustaches (AngularJS expression) in the directive template like so: ng-show="showspinner"
but this makes it worse by just rendering to ng-show="showspinner"
instead of ng-show="false"
.
Following is my code.
The $ctrl.result
is loaded asynchronously while the $ctrl.resultsLoading
is set to true
, when the results are done loading it's set to false
:
<report-tile
title="My Report Item"
value="{{$ctrl.result.count|number:0}}"
loading="{{$ctrl.resultsLoading}}">
</report-tile>
This is my ReportTileDirective.js
(function(angular) {
"use strict";
angular
.module("app")
.directive(
"reportTile",
["$templateCache", "$compile" ,function($templateCache, $compile) {
return {
restrict: "EA",
scope: {
title: "@",
value: "@",
loading: "@"
},
link: function (scope, element, attribues) {
scope.showspinner = false;
scope.$watch("loading",
function () {
scope.showspinner = attribues.loading;
console.log("watching::loading::" + attribues.loading);
});
},
templateUrl: "app/directives/ReportTileDirective.html"
};
}]);
}(window.angular));
This is my ReportTileDirective.html
<div class="col-sm-4 col-md-3 col-lg-2 col-padding">
<div class="panel panel-default">
<div class="panel-heading tile-title">
<strong>{{title === '' ? 'Loading' : title}}</strong>
</div>
<div class="panel-body" style="text-align: right">
<strong>
<i ng-show="{{showspinner}}" class="fa fa-refresh fa-spin"></i>
{{value === '' ? 0 : value}}
</strong>
</div>
</div>
Finally this is the rendered DOM (as shown in the Chrome debugger Elements tab) when loading is done and it switches to true
, the ng-hide
is not removed:
<i ng-show="true" class="fa fa-refresh fa-spin ng-hide"></i>
Please help! Thank you!
I found my question is a duplicate of this one and thanks to @CodeWarrior's answer I was able to fix this. I can remove the whole link:
section and use the loading
parameter directly if: I bind it with =
instead of @
and then get rid of the expression syntax, so that this is evaluated in the directive rather than beforehand.
So my directive usage changes to:
<report-tile
title="My Report Item"
value="{{$ctrl.result.count|number:0}}"
loading="$ctrl.resultsLoading"> <!-- notice no mustaches here -->
</report-tile>
and my directive JavaScript file changes to:
(function(angular) {
"use strict";
angular
.module("app")
.directive(
"reportTile",
["$templateCache", "$compile" ,function($templateCache, $compile) {
return {
restrict: "EA",
scope: {
title: "@",
value: "@",
loading: "=" /* notice the = binding */
},
templateUrl: "app/directives/ReportTileDirective.html"
};
}]);
}(window.angular));
Then finally my directive template changes to:
<div class="col-sm-4 col-md-3 col-lg-2 col-padding">
<div class="panel panel-default">
<div class="panel-heading tile-title">
<strong>{{title === '' ? 'Loading' : title}}</strong>
</div>
<div class="panel-body" style="text-align: right">
<strong>
<i ng-show="loading" class="fa fa-refresh fa-spin"></i> <!-- notice to mustaches here -->
{{value === '' ? 0 : value}}
</strong>
</div>
</div>