Hallgeir
Hallgeir

Reputation: 1273

AngularJS controllerAs: updating controller field in $interval does not update ng-show

I'm using the controllerAs syntax, and for some reason, when updating a controller's field in an $interval, it doesn't show/hide elements in the view properly. I use angular's UI router.

The issue is best described with code I think, so please forgive the code dump.

My state (the "refreshLogs" simply is a function to call the logService for an updated log):

angular.module('portal')
.config(function ($stateProvider, $urlRouterProvider) {
    $stateProvider
         .state('logs', {
             'abstract': true,
             views: {
                 "@": { template: '<div ui-view></div>' }
             }
         })
        .state('logs.view', {
            url: '/logs/:id',
            resolve: {
                log: function ($stateParams, logService) {
                    return logService.getLog($stateParams.id);
                },
                refreshLog: function ($stateParams, logService) {
                    var id = $stateParams.id

                    var fn = function (id) {
                        return logService.getLog(id)
                    };

                    return function() { return fn(id) }
                }
            },
            templateUrl: '/app/logs/viewlog.html',
            controller: 'logController',
            controllerAs: 'vm'
        })
});

My controller:

angular.module('portal.controllers')
.controller('logController', function ($state, log, refreshLog, $scope, $interval) {
    var vm = this;
    vm.log = log;

    vm.refreshTimer = $interval(function () {
        refreshLog().then(function (data) {
            vm.log = data;
        })
    }, 15000);

    $scope.$on("$destroy", function () {
        if (angular.isDefined(vm.refreshTimer)) {
            $interval.cancel(vm.refreshTimer);
        }
    });
});

And finally the view:

<div ng-show="{{ vm.log != null }}">
    <div class="page-header">
        <h1>{{ vm.log.JobType }} ({{ vm.log.JobResult }})</h1>
    </div>

    Parameters: {{ vm.log.JobParameters }}

<pre>{{ vm.log.Content }}</pre>
</div>

<div ng-show="{{ vm.log == null }}">
    <div class="page-header">
        <h1>Waiting for log...</h1>
    </div>
</div>

It appears the "ng-show" value in the DOM updates, but the elements are NOT shown/hidden based on this value. I inspected the DOM in Chrome, and I see this (asterisks added for emphasis):

<div ui-view="" class="ng-scope"><div ng-show="**false**" class="ng-binding ng-scope ng-hide">
    <div class="page-header">
        <h1 class="ng-binding"> ()</h1>
    </div>

    Parameters: 

<pre class="ng-binding"></pre>
</div>

<div ng-show="**true**" class="ng-scope">
    <div class="page-header">
        <h1>Waiting for log...</h1>
    </div>
</div></div>

Which is correct to start with, and the proper divs are shown. After a few seconds, the log is refreshed, and the "vm.log" variable is set to a non-null value (I know this because I set a breakpoint in the JS code assigning this value, and it looks correct). Afterwards, I inspect the DOM again and see this:

<div ui-view="" class="ng-scope"><div ng-show="**true**" class="ng-binding ng-scope ng-hide">
    <div class="page-header">
        <h1 class="ng-binding">...</h1>
    </div>
...
</pre>
</div>

<div ng-show="**false**" class="ng-scope">
    <div class="page-header">
        <h1>Waiting for log...</h1>
    </div>
</div></div>

Notice the "ng-show" attributes showing the correct values. So, the expression has obviously been re-evaluated. However, the old "Waiting for log..." header still shows, and the first div is NOT shown (and it still has the "ng-hide" css class applied).

What am I missing here?

Upvotes: 2

Views: 444

Answers (1)

Hallgeir
Hallgeir

Reputation: 1273

As Ranjith S pointed out in the comment, the issue was in the ng-show binding! There should be no {{ ... }}s in there. Removing the brackets solved the issue.

Upvotes: 1

Related Questions