0

I have a directive which is a toggle button to change the theme of the page.

The code for the directive is...

app.directive('twoOptionThemeSwitch', function () {
    return {
        scope: {},
        restrict: 'A',
        replace: 'true',
        templateUrl: 'app/themes/partials/twoOptionThemeSwitch.html',
        controller: 'twoOptionThemeSwitch',
        link: function (scope, elem, attrs) {
            elem.bind('click', scope.switchTheme);
        }
    };
});

The controller for this is...

app.controller('twoOptionThemeSwitch', function ($scope, $rootScope) {

    $rootScope.$on('switchTheme', function (event, theme) {
        $scope.selectedTheme = theme;
        $scope.inverseButton = theme == 'theme-dark';
    });

    $scope.switchTheme = function () {
        if ($scope.selectedTheme == 'theme-bright') {
            $rootScope.$broadcast('switchTheme', 'theme-dark');
        } else {
            $rootScope.$broadcast('switchTheme', 'theme-bright');
        }
    }

    $rootScope.$broadcast('switchTheme', 'theme-bright');
});

and here is the markup...

<div class="btn-group" data-toggle="buttons" id="theme-switcher">
    <label class="btn" ng-class="{'btn-inverse' : inverseButton, 'active' : !inverseButton}">
        <input type="radio" name="theme-switcher"><i class="icon-sun"></i> Bright
    </label>
    <label class="btn" ng-class="{'btn-inverse' : inverseButton, 'active' : inverseButton}">
        <input type="radio" name="theme-switcher"><i class="icon-moon"></i> Dark
    </label>
</div>

When I call the $broadcast from the controller during initialization it set the classes correctly. However when I click the button the classes do not change but when debugging I noticed that $on is fired correctly so I know the scope variables are getting set.

Brett
  • 321
  • 4
  • 15
  • Events (like ones bound to DOM elements with `.bind()`) occur outside of Angular. That means Angular can't update the views, because it doesn't know the event happened. The quick fix would be to change your event binding to be: `elem.bind('click', function () { scope.$apply(function () { scope.switchTheme(); }});`. Using `scope.$apply`, it forces Angular to run a digest cycle, which syncs the views – Ian Jul 28 '14 at 18:29
  • When I set a breakpoint in $scope.switchTheme amd it is being called when I click the button – Brett Jul 28 '14 at 18:32
  • 1
    I understand that - that's the problem. **Only** the JavaScript is executing...the view is not updating. That's because the event is occurring outside of Angular, so Angular doesn't know it's happening. Sure, the code is executing, but that doesn't mean Angular knows to update the view. Remember, there's a two-way binding between the JS and the HTML - it's not magical. Angular needs to know that something in the scope has changed, so `scope.$apply` causes this. The binding is the problem here. – Ian Jul 28 '14 at 18:34
  • Ian you're right. I changed the directive to use ng-click instead of a jquery bind and now it's working correctly. Thanks for the advice – Brett Jul 28 '14 at 19:01

0 Answers0