1

I’m hoping there are some Angular 1.x experts who can show me what I’m doing wrong. I have a simple function to update which of 3 buttons in a “tab group” is the current one. This function is called whenever any of the buttons is clicked.

        $scope.updateFilter = function (type, value) {
            // Additional unrelated code here ...

           document.getElementsByClassName('active')[0].className = document.getElementsByClassName('active')[0].className.replace(' active', '');
           document.getElementById('tabButton_' + value).className += ' active';
           $scope.$apply();
        };

The background color of the current button is indeed highlighted but only AFTER one clicks elsewhere on the screen. In other words, it’s not updated instantly like it should.

Any ideas how to correct this?

1
  • I can probably shed some light on why you are seeing the behavior you are if you can produce a quick demo app showing the problem. Tough to say because I don't know how $scope.updateFilter is being invoked at the moment (via ng-click, some externally attached handler, etc.). Commented Jan 30, 2019 at 20:16

1 Answer 1

2

It's hard to diagnose the issue without seeing some more code or a reproduction of your existing issue. However, from the above, you are certainly not doing the "angularjs" way. A more angular approach would be to use bindings and update the model as the user clicks different button options. A very basic (and ugly styled) example:

angular.module('myApp', [])
  .controller('MainController', function () {
    var self = this;
    
    self.$onInit = function $onInit() {
      // These will be ng-repeated over for the example
      self.buttons = [
        'Option 1',
        'Option 2',
        'Option 3'
      ];

      // This is the model binding that will drive the active style
      self.activeIndex = 0;
    };
    
    self.setActiveIndex = function setActiveIndex(index) {
      // This is called on button click and updates the model used
      // for the active button styling
      self.activeIndex = index;
    };
  });
.active {
  background: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<!-- repeat the buttons. when clicked, call controller method to update model's active index -->
<div ng-app="myApp" ng-controller="MainController as $ctrl">
  <button ng-repeat="b in $ctrl.buttons" type="button" ng-class="{active: $ctrl.activeIndex===$index}" ng-click="$ctrl.setActiveIndex($index)">{{::b}}</button>
</div>

Take aways:

  • You probably shouldn't be doing DOM manipulation. Use existing directives and model binding, else you are losing many of the benefits you are supposed to get from angularjs.
  • Don't call $scope.$apply(). Angular will do this for you if you are using an ng-click in your template (which you probably should instead of building the event listeners yourself).
Sign up to request clarification or add additional context in comments.

2 Comments

Patrick, thank you for this! Your comment echoes the feedback I've retrieved internally later. I'm entirely new to Angular and forced to work with Angular 1x (aka AngularJS) because of existing code. Learning as I go.
The paradigm shift takes time... Then just when you learn it you'll have to switch to something new again as is the ever evolving world of js.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.