29

I am trying to create a toggle button in Angular. What I have so far is:

<div class="btn-group">
  <a class="btn btn-primary pull-right"
     ng-click="toggleArchive(true)"
     ng-show="!patient.archived">Archive patient</a>
  <a class="btn btn-danger pull-right"
     ng-click="toggleArchive(false)"
     ng-show="patient.archived">Unarchive patient</a>
  .... some other buttons ....
</div>

Basically I achieve toggling, by having TWO buttons, and toggling between them. This is causing issues because the ng-hide just adds a display:none style to the button when it's hidden, which is causing me styling issues. Ideally I want to have ONE button, that has it's text, class and function call changed depending on the state of patient.archived.

What's a clean way to achieve this?

1

6 Answers 6

56

You should use ng-class to toggle between classes and bind the text with a regular Angular expression. Also, if your function toggleArchive only toggle the value, you can remove it and toggle the value from an Angular expression:

<a class="btn pull-right" 
   ng-class="{true: 'btn-primary', false: 'btn-danger'}[!patient.archived]"
   ng-click="patient.archived = !patient.archived">
  {{!patient.archived && 'Archive' || 'Unarchive'}} patient
</a>
Sign up to request clarification or add additional context in comments.

4 Comments

I considered this, and I realise it can be done, but it feels like their's a bit too much going on within the view that could be pushed onto a directive. Thoughts?
Directive is a good way to encapsulate reusable widgets. So if it's a common widget, or if you believe this is going to hit performance somehow, maybe it would worth a directive. Take a look here, where I share my thoughts about when to write a directive.
Your logic is backwards. It's actually class: condition, not condition: class
That's actually not necessarily true @AndrewRhyne. You can use condition: class when you use it like a Switch, for example: {'costumer': 'costumer-class', 'admin': 'admin-class'}[user.type]. In the case above, I just wanted to avoid writing the condition twice (!patient.archived and patient.archived)
2

for any other weary traveller...

you could simply have used ng-if. ng-if completely excludes the element from the DOM if false, so you'd have no issues with styles when not displayed. Also there is not really a need for the button group you could just change the text of the button

Something like this:

<button class="btn btn-primary pull-right"
        ng-click="toggleArchive(true)"
        ng-if="!patient.archived">Archive patient</button>
<button class="btn btn-danger pull-right"
        ng-click="toggleArchive(false)"
        ng-if="patient.archived">Unarchive patient</button>

Comments

2

It might help you:

<html>

<head>
  <script src="js/angular.js"></script>
  <script src="js/app.js"></script>
  <link rel="stylesheet" href="css/bootstrap.css">
</head>

<body ng-app>
  <div ng-controller="MyCtrl">
    <button ng-click="toggle()">Toggle</button>
    <p ng-show="visible">Hello World!</p>
  </div>
</body>

</html>
function MyCtrl($scope) {
  $scope.visible = true;
  $scope.toggle = function() {
    $scope.visible = !$scope.visible;
  };
}

Comments

1

This may Help:

<!-- Include Bootstrap-->
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.3.js"></script>

<!-- Code -->
<a href="#" ng-model="collapsed" ng-click="collapsed=!collapsed">Click here to <strong>Toggle (show/hide)</strong> description</a>

Comments

1
<input type="checkbox" class="toggle-button"
       ng-model="patient.archived">

Then style the checkbox like a button.

if the toggle needs to do more things, add the following to your patient class:

class Patient {
  constructor() {
    this.archived = false;
  }
  ...
  get angularArchived() {
    return this.archived;
  }
  set angularArchived(value) {
    if (value !== this.archived) {
      toggleArchived(value);
    }
    this.archived = value;
  }
}

then use

<input type="checkbox" class="toggle-button"
       ng-model="patient.angularArchived">

Comments

1

This is the simplest answer I've found. I haven't tried it with animations because I just use it for quick setup.

<a ng-click="scopeVar=scopeVar!=true">toggle</a>

<div ng-show="scopeVar">show stuff</div>

with scopeVar=scopeVar!=true undefined becomes true.

Comments

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.